我应该在环境路径名中使用引号吗?

Should I use quotes in environment path names?

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

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

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

Google shell style guide suggests avoiding quotes for path names. In contrast, a lot of the popular dotfiles repos (such as Zach Holman's here) 使用引号。是否存在在路径中使用引号有优势的情况?

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

PATH=test 123

会return:

123: command not found

甚至

export PATH=test 123

这将 return

bash export: `123': not a valid identifier

它是否回答了您的问题?

老实说,我不会遵循这样的第四方风格指南。虽然我很惊讶甚至 Google 宣传这样错误的建议。

我会关注:

(需慎重延伸)

@gniourf_gniourf and @chepner 致敬,寻求他们的帮助。

tl;dr

为了安全起见,双引号:它适用于所有情况,跨越所有 POSIX-like shells.

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


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

  • 双引号是 可选的,仅当 文字 部分是您的 RHS(要分配的值)既不包含空格也不包含其他 shell 元字符。
  • 引用的变量的值是否包含whitespace/metacharacters与无关紧要-见下文。
    • 再说一遍:sh 有关系,当使用 export 时,所以总是用双引号。

在这种情况下不用双引号就可以逃脱的原因是 变量赋值 语句在 POSIX-like shells 解释他们的 RHS 不同于 arguments 传递给 commands,如所述在 POSIX 规范的 section 2.9.1 中:

  • 具体来说,即使初始分词,它只应用于unexpanded (raw) RHS(这就是为什么你 do 需要在 literals 中用 whitespace/metacharacters 引用,和不是它的结果.

  • 仅适用于正版形式的赋值语句
    <name>=<value> in all POSIX-like shells
    ,即如果没有no command name变量名前;请注意,这包括分配 prepended 到命令以为其定义临时环境变量,例如 foo=$bar cmd ....

  • 赋值在其他命令的上下文中应该总是用双引号,为了安全:

    • sh(在(大部分)严格POSIX兼容的shell中,例如dash)与[=23=的赋值] 被视为 常规命令 foo=$bar 部分被视为 第一个参数 export 内置因此照常处理(也受 结果 的分词影响)。
      (POSIX 没有指定涉及(显式)变量赋值的任何其他命令;declaretypesetlocal 是非标准的 扩展 ).

    • bashkshzsh,在与 POSIX 的可理解偏差中,将赋值逻辑扩展到 export foo=$bartypeset/declare/local foo=$bar 还有。换句话说:bashkshzshexport/typeset/declare/local命令被视为assignments,所以引用不是绝对必要的.

      • 也许令人惊讶的是,dash,它也选择了实现 non-POSIX local builtin[2 ] , 不向其扩展赋值逻辑;但是,它与其 export 行为一致。
    • 传递给 env 的赋值(例如,env foo=$bar cmd ...)也作为命令参数进行扩展,因此需要双引号 - 除了 zsh .

      • envkshbash 中的行为不同于 export 是因为 env外部实用程序,而exportshell内置.
        zsh 的行为 从根本上 与其他 shell 的行为在涉及未引用的变量引用时不同。
  • Tilde (~) 扩展发生在 genuine 赋值语句:

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

例子

此示例演示了在 bashkshzsh 中,即使使用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 指出的:使用 export 修改 PATH 的值是可选的,因为一旦变量被标记为已导出,您就可以使用常规赋值 (PATH=...) 来更改其值。
也就是说,您仍然可以选择使用export,以明确导出被修改的变量。

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

我在 docker .env 文件中设置环境路径名时使用了上面的这些答案,并且得到了位。我把它放在这里是为了其他任何正在寻找如何为 docker.

定义环境变量的人

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

然而,docker compose 不需要将值用引号括起来,而是需要不带引号定义的环境变量,除非引号是值的一部分。同样,如上文url所述

There is no special handling of quotation marks (i.e. they will be part of the VAL, you have been warned ;)

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