bash 我应该在环境路径名中使用引号吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33318499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should I use quotes in environment path names?
提问by Cabbage soup
I'm in the process of cleaning up all my config files in an attempt to make them as readable as possible. I've been looking for a style guide on the use of quotes while exporting paths in, for example, a ~/.bashrc
file:
我正在清理我所有的配置文件,试图使它们尽可能可读。我一直在寻找有关在导出路径时使用引号的样式指南,例如,~/.bashrc
文件:
export PATH="/users/me/path:$PATH"
vs
对比
export PATH=/users/me/path:$PATH
The Google shell styleguide suggests avoiding quotes for path names. In contrast, a lot of the popular dotfiles repos (such as Zach Holman's here) use quotes. Are there any situations when it is an advantage to use quotes in the path?
Google shell 风格指南建议避免路径名的引号。相比之下,许多流行的点文件存储库(例如 Zach Holman 的这里)使用引号。在路径中使用引号是否有优势?
采纳答案by mklement0
Tip of the hat to @gniourf_gniourfand @chepnerfor their help.
帽子的提示来@gniourf_gniourf和@chepner他们的帮助。
tl;dr
tl;博士
To be safe, double-quote: it'll work in all cases, across all POSIX-like shells.
为了安全起见,双引号:它适用于所有情况,适用于所有类似 POSIX 的 shell。
If you want to add a ~
-based path, selectivelyleave the ~/
unquotedto ensure that ~
is expanded; e.g.: export PATH=~/"bin:$PATH"
.
See below for the rules of ~
expansion in variable assignments.
Alternatively, simply use $HOME
inside a single, double-quoted string:export PATH="$HOME/bin:$PATH"
如果要添加~
-based 路径,请选择性地保留不带~/
引号的以确保~
扩展;例如:export PATH=~/"bin:$PATH"
。
有关~
变量赋值中的扩展规则,请参见下文。
或者,只需$HOME
在单个双引号字符串中使用:export PATH="$HOME/bin:$PATH"
NOTE: The following applies to bash
, ksh
, and zsh
, but NOT to (mostly) strictly POSIX compliant shells such as dash
; thus, when you target /bin/sh
, you MUST double-quote the RHS of export
.[1]
注意:以下内容适用于bash
、ksh
和zsh
,但不适用于(大部分)严格符合 POSIX 的 shell,例如dash
; 因此,当您定位 时/bin/sh
,您必须双引号export
. [1]
- Double-quotes are optional, ONLY IF the literalpart of your RHS (the value to assign) contains neither whitespace nor other shell metacharacters.
- Whether the values of the variables referencedcontain whitespace/metacharacters or not does notmatter - see below.
- Again: It doesmatter with
sh
, whenexport
is used, so always double-quote there.
- Again: It doesmatter with
- 双引号是可选的,仅当RHS的文字部分(要分配的值)既不包含空格也不包含其他 shell 元字符时。
- 引用的变量的值是否包含空格/元字符并不重要 - 见下文。
- 还是那句话:它确实与物质
sh
,当export
被使用,所以总是双引号那里。
- 还是那句话:它确实与物质
The reason you can get away without double-quoting in this case is that variable-assignmentstatements in POSIX-like shells interpret their RHS differentlythan argumentspassed to commands, as described in section 2.9.1of the POSIX spec:
在这种情况下,您无需使用双引号就可以逃脱的原因是,类POSIX 的 shell中的变量赋值语句对它们的 RHS 的解释与传递给commands 的参数不同,如POSIX 规范的第 2.9.1 节所述:
Specifically, even though initialword-splitting isperformed, it is only applied to the unexpanded(raw) RHS (that's why you doneed quoting with whitespace/metacharacters in literals), and not to its results.
This only applies to genuineassignment statements of the form
<name>=<value>
in allPOSIX-like shells, i.e., if there is no command namebefore the variable name; note that that includes assignments prependedto a command to define ad-hoc environment variables for it, e.g.,foo=$bar cmd ...
.Assignments in the context of other commandsshould always be double-quoted, to be safe:
With
sh
(in a (mostly) strictly POSIX-compliant shell such asdash
) an assignment withexport
is treated as a regular command, and thefoo=$bar
part is treated as the 1st argumentto theexport
builtin and therefore treated as usual (subject to word-splitting of the result, too).
(POSIX doesn't specify any other commands involving (explicit) variable-assignment;declare
,typeset
, andlocal
are nonstandard extensions).bash
,ksh
,zsh
, in an understandable deviation from POSIX, extend the assignment logic toexport foo=$bar
andtypeset/declare/local foo=$bar
as well. In other words: inbash
,ksh
,zsh
,export/typeset/declare/local
commands are treated like assignments, so that quoting isn't strictly necessary.- Perhaps surprisingly,
dash
, which also chose to implement the non-POSIXlocal
builtin[2], does NOT extend assignment logic to it; it is consistent with itsexport
behavior, however.
- Perhaps surprisingly,
Assignments passed to
env
(e.g.,env foo=$bar cmd ...
) are also subject to expansion as a command argument and therefore need double-quoting - except inzsh
.- That
env
acts differently fromexport
inksh
andbash
in that regard is due to the fact thatenv
is an external utility, whereasexport
is a shell builtin.
(zsh
's behavior fundamentallydiffers from that of the other shells when it comes to unquoted variable references).
- That
Tilde (
~
) expansion happens as follows in genuineassignment statements:- In addition to the
~
needing to be unquoted, as usual, it is also only applied:- If the entireRHS is
~
; e.g.:foo=~ # same as: foo="$HOME"
- Otherwise: onlyif bothof the following conditions are met:
- if
~
starts the string or is preceded by an unquoted:
- if
~
is followed by an unquoted/
. - e.g.,
foo=~/bin # same as foo="$HOME/bin"
foo=$foo:~/bin # same as foo="$foo:$HOME/bin"
- if
- If the entireRHS is
- In addition to the
具体地讲,即使最初的字分裂的进行,但仅适用于未展开的(原始)RHS(这就是为什么你做需要在空白/元字符引用文字),而不是其结果。
这仅适用于所有类似 POSIX 的 shell 中形式的真正赋值语句
<name>=<value>
,即,如果变量名之前没有命令名;请注意,这包括添加到命令前的赋值,以便为其定义临时环境变量,例如foo=$bar cmd ...
.为安全起见,其他命令上下文中的赋值应始终用双引号引起来:
用
sh
(在(符合POSIX标准的大部分)严格壳例如dash
)与分配export
被视为常规命令,并且foo=$bar
部分被视为第一参数的export
内置和因此处理照常(视的字分割结果也是)。
(POSIX不指定涉及(显式)可变分配的任何其它命令;declare
,typeset
,和local
是非标准的扩展)。bash
,ksh
,zsh
, 与 POSIX 有一个可以理解的偏差,将赋值逻辑扩展到export foo=$bar
和typeset/declare/local foo=$bar
。换句话说:inbash
,ksh
,zsh
,export/typeset/declare/local
命令被视为赋值,因此引用不是绝对必要的。- 也许令人惊讶的是,
dash
也选择实现非-POSIXlocal
内置[2],并没有将赋值逻辑扩展到它;export
然而,这与其行为一致。
- 也许令人惊讶的是,
传递给
env
(例如,env foo=$bar cmd ...
)的赋值也可以作为命令参数进行扩展,因此需要双引号 - 除了 inzsh
。- 这
env
与export
inksh
和bash
在这方面的行为不同是因为它env
是一个外部实用程序,而它export
是一个内置的 shell。
(当涉及到不带引号的变量引用时,zsh
的行为与其他 shell的行为根本不同)。
- 这
波浪号 (
~
) 扩展在真正的赋值语句中发生如下:- 除了
~
需要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"
- if
- 如果整个RHS 是
- 除了
Example
例子
This example demonstrates that in bash
, ksh
, and zsh
you can get away withoutdouble-quoting, even when using export
, but I do not recommend it.
这个例子演示了 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] As @gniourf_gniourf points out: Use of export
to modifythe value of PATH
is optional, because once a variable is marked as exported, you can use a regular assignment (PATH=...
) to change its value.
That said, you may still chooseto use export
, so as to make it explicit that the variable being modified is exported.
[1] 正如@gniourf_gniourf 指出的那样:使用 ofexport
来修改的值PATH
是可选的,因为一旦变量被标记为导出,您就可以使用常规赋值 ( PATH=...
) 来更改其值。
也就是说,您仍然可以选择使用export
,以便明确导出正在修改的变量。
[2] @gniourf_gniourf states that a future version of the POSIX standard may introduce the local
builtin.
[2] @gniourf_gniourf 指出 POSIX 标准的未来版本可能会引入local
内置。
回答by hek2mgl
test 123
is a valid path name on UNIX. Try
test 123
是 UNIX 上的有效路径名。尝试
PATH=test 123
It will return:
它将返回:
123: command not found
Or even
甚至
export PATH=test 123
which will return
这将返回
bash export: `123': not a valid identifier
Does it answer your question?
它回答你的问题吗?
Honestly I would not follow such fourth party style guides. Although I'm astonished that even Google advertises such wrong advices.
老实说,我不会遵循这样的第四方风格指南。尽管令我惊讶的是,即使是 Google 也会宣传这种错误的建议。
I would follow:
我会遵循:
- http://www.tldp.org/LDP/Bash-Beginners-Guide/html/Bash-Beginners-Guide.html
- http://www.tldp.org/LDP/abs/html/
- https://www.gnu.org/software/bash/manual/bash.html
- http://www.tldp.org/LDP/Bash-Beginners-Guide/html/Bash-Beginners-Guide.html
- http://www.tldp.org/LDP/abs/html/
- https://www.gnu.org/software/bash/manual/bash.html
(to be carefully extended)
(需谨慎扩展)
回答by Fralcon
I used these answers above when setting environment path names in a docker .env file, and got bit. I'm putting this here for anyone else looking for how to define environment variables for docker.
我在 docker .env 文件中设置环境路径名时使用了上面的这些答案,并得到了一些。我把它放在这里供其他任何人寻找如何为 docker 定义环境变量。
Docker compose reads environment variables from an .env file that exists in the same folder that docker compose is run as stated here https://docs.docker.com/compose/env-file.
Docker compose 从 .env 文件中读取环境变量,该文件位于运行 docker compose 的同一文件夹中,如此处所述https://docs.docker.com/compose/env-file。
However instead of wrapping the value in quotes, docker compose needs the environment variable defined without quotes, unless the quotes are part of the value. Again, as stated in the url above
然而,docker compose 不需要将值括在引号中,而是需要定义不带引号的环境变量,除非引号是值的一部分。同样,如上面的网址中所述
There is no special handling of quotation marks (i.e. they will be part of the VAL, you have been warned ;)
没有对引号进行特殊处理(即它们将成为 VAL 的一部分,您已被警告;)
I was trying to set NODE_PATH=./src
for absolute paths to work in a react app being deployed by docker, but had written it as NODE_PATH="./src"
. This warning pulled me out of 4 hour rabbit hole.
我试图设置NODE_PATH=./src
绝对路径以在 docker 部署的 React 应用程序中工作,但已将其编写为NODE_PATH="./src"
. 这个警告把我从 4 小时的兔子洞里拉了出来。