50

我正在清理我的所有配置文件,以使它们尽可能可读。我一直在寻找关于在导出路径时使用引号的样式指南,例如,~/.bashrc文件:

export PATH="/users/me/path:$PATH"

对比

export PATH=/users/me/path:$PATH

Google shell 样式指南建议避免路径名使用引号。相比之下,许多流行的 dotfiles 存储库(例如 Zach Holman 的此处)使用引号。在路径中使用引号是否有优势?

4

3 回答 3

42

@gniourf_gniourf@chepner 致敬以寻求帮助。

tl;博士

为了安全起见,双引号:它适用于所有情况,适用于所有类似 POSIX 的 shell。

如果要添加~基于 - 的路径,请选择性地保留~/ 未引用的路径以确保~扩展;例如:export PATH=~/"bin:$PATH"变量赋值的扩展规则见下文。~
或者,只需$HOME在单个双引号字符串中使用:
export PATH="$HOME/bin:$PATH"


注意:以下适用于bashkshzsh,但不适用于(大部分)严格符合 POSIX 的 shell,例如dash; 因此,当您定位. 时/bin/sh,您必须双引号export. [1]

  • 双引号是可选的,仅当您的 RHS 的文字部分(要分配的值)既不包含空格也不包含其他 shell 元字符时。
  • 引用的变量的值是否包含空格/元字符无关紧要- 见下文。
    • 再说一遍:, when使用确实很重要,所以总是在那里加双引号。shexport

在这种情况下你可以不用双引号就可以逃脱的原因是POSIX-like shell 中的变量赋值语句解释它们的 RHS与传递给commands参数不同,如POSIX 规范的第 2.9.1 节所述:

  • 具体来说,即使执行了初始分词,也仅适用于未扩展的(原始)RHS(这就是为什么您需要在literals中使用空格/元字符引用),而不是其results

  • 仅适用于所有类似 POSIX 的 shell中形式的真正赋值语句
    <name>=<value>
    ,即,如果变量名之前没有命令名;请注意,这包括附加到命令以为其定义临时环境变量的分配,例如foo=$bar cmd ....

  • 为了安全起见,其他命令上下文中的赋值应始终用双引号引起来:

    • 对于sh(在(大部分)严格符合 POSIX 的 shell 中,例如dash),赋值 withexport被视为常规命令,并且该foo=$bar部分被视为内置函数的第一个参数export因此被视为通常处理(受结果,也是)。
      (POSIX 没有指定任何其他涉及(显式)变量赋值的命令;declare、、typesetlocal是非标准扩展)。

    • bash, ksh, zsh, 在与 POSIX 的一个可以理解的偏差中,将赋值逻辑扩展到export foo=$bartypeset/declare/local foo=$bar。换句话说:in bash, ksh, zsh,export/typeset/declare/local命令被视为assignments,因此引用不是绝对必要的。

      • 也许令人惊讶的是dash,它也选择实现-POSIXlocal内置[2] ,并没有将分配逻辑扩展到它;然而,它与它的export行为是一致的。
    • 传递给env(例如,env foo=$bar cmd ...)的赋值也可以作为命令参数进行扩展,因此需要双引号 - 除了 in zsh

      • 这与in和在这方面的env行为不同是因为它是一个外部实用程序,而它是一个内置的 shell。 (在涉及未引用的变量引用时,其行为与其他 shell的行为根本不同)。exportkshbashenvexport
        zsh
  • 波浪号 ( ) 扩展在真正的赋值语句~中发生如下

    • 除了~需要被unquoted之外,像往常一样,它也只适用:
      • 如果整个RHS 是~; 例如:
        • foo=~ # same as: foo="$HOME"
      • 否则:满足以下两个条件时:
        • if~开始字符串或前面有一个不带引号的 :
        • if~后跟一个未引用 /的.
        • 例如,
          foo=~/bin # same as foo="$HOME/bin"
          foo=$foo:~/bin # same as foo="$foo:$HOME/bin"

例子

这个例子展示了 in bash, ksh, 并且你可以不用zsh双引号就可以逃脱,即使使用,但我不推荐它export

#!/usr/bin/env bash
# or ksh or zsh - but NOT /bin/sh!

# Create env. variable with whitespace and other shell metacharacters
export FOO="b:c &|<> d"

# Extend the value - the double quotes here are optional, but ONLY 
# because the literal part, 'a:`, contains no whitespace or other shell metacharacters.
# To be safe, DO double-quote the RHS.
export FOO=a:$foo # OK - $FOO now contains 'a:b:c &|<> d'

[1] 正如@gniourf_gniourf 指出的那样:使用 ofexport修改的值PATH是可选的,因为一旦将变量标记为导出,您就可以使用常规赋值 ( PATH=...) 来更改其值。
也就是说,您仍然可以选择使用export,以便明确表示正在修改的变量已导出。

[2] @gniourf_gniourf 声明 POSIX 标准的未来版本可能会引入local内置函数。

于 2015-10-24T13:43:34.713 回答
11

在 docker .env 文件中设置环境路径名时,我使用了上面的这些答案,并且有点。我把这个放在这里是为了给其他寻找如何为 docker 定义环境变量的人。

Docker compose 从 .env 文件中读取环境变量,该文件位于运行 docker compose 的同一文件夹中,如此处所述https://docs.docker.com/compose/env-file。

但是,docker compose 不需要将值包装在引号中,而是需要在没有引号的情况下定义环境变量,除非引号是值的一部分。同样,如上面的网址所述

引号没有特殊处理(即它们将成为 VAL 的一部分,您已被警告;)

我试图设置NODE_PATH=./src绝对路径以在 docker 部署的反应应用程序中工作,但已将其编写为NODE_PATH="./src". 这个警告把我从 4 小时的兔子洞里拉了出来。

于 2018-01-23T21:35:38.090 回答
4

test 123是 UNIX 上的有效路径名。尝试

PATH=test 123

它将返回:

123: command not found

甚至

export PATH=test 123

这将返回

bash export: `123': not a valid identifier

它回答了你的问题吗?

老实说,我不会遵循这样的第四方风格指南。虽然我很惊讶,即使是谷歌也宣传了这样的错误建议。

我会遵循:

(需谨慎扩展)

于 2015-10-24T13:31:53.900 回答