six*_*ude 27 command-line shell bash environment-variables
我的一位同事为我提供了一种我不熟悉的 Bash 语法。我的 Google foo 无法弄清楚它的作用以及为什么/何时应该使用它。
他发给我的命令是这样的:
someVariable=something command
Run Code Online (Sandbox Code Playgroud)
最初,我认为这等效于以下内容:
someVariable=something ; command
Run Code Online (Sandbox Code Playgroud)
或者
someVariable=something
command
Run Code Online (Sandbox Code Playgroud)
但事实并非如此。例子:
[Jan-03 11:26][~]$ # Look at the environment variable BAZ. It is currently empty
[Jan-03 11:26][~]$ echo $BAZ
[Jan-03 11:27][~]$ # Try running a command of the same format
[Jan-03 11:27][~]$ BAZ=jake echo $BAZ
[Jan-03 11:27][~]$
[Jan-03 11:27][~]$ # Now, echo BAZ again. It is still empty:
[Jan-03 11:27][~]$ echo $BAZ
[Jan-03 11:27][~]$
[Jan-03 11:28][~]$
[Jan-03 11:28][~]$ # If we add a semi-colon to the command, we get dramatically different results:
[Jan-03 11:28][~]$ BAZ=jake ; echo $BAZ
jake
[Jan-03 11:28][~]$
[Jan-03 11:28][~]$ # And we can see that the variable is actually set:
[Jan-03 11:29][~]$ echo $BAZ
jake
[Jan-03 11:29][~]$
Run Code Online (Sandbox Code Playgroud)
这个语法有什么作用?已设置的变量会发生什么变化?为什么这样做?
xhi*_*nne 39
这相当于:
( export someVariable=something; command )
Run Code Online (Sandbox Code Playgroud)
这将创建someVariable一个具有指定值的环境变量,但仅适用于正在运行的命令。
以下是bash手册的相关部分:
简单命令
一个简单的命令是一系列可选的变量赋值,后跟空格分隔的单词和重定向,并由控制运算符终止。第一个字指定要执行的命令,并作为参数零传递。其余的词作为参数传递给调用的命令。
(……)
简单的命令扩展
如果[来自命令扩展]没有命令名称产生,则变量赋值会影响当前的 shell 环境。否则,变量会被添加到执行命令的环境中,不会影响当前的 shell 环境。
注意:请记住,这不是特定于bash,而是由 POSIX 指定的。
编辑 - 从答案中的评论总结讨论
BAZ=JAKE echo $BAZ不打印 JAKE的原因是因为变量替换是在其他任何事情之前完成的。如果您绕过变量替换,这将按预期运行:
$ echo_baz() { echo "[$BAZ]"; }
$ BAZ=Jake echo_baz
[Jake]
$ echo_baz
[]
Run Code Online (Sandbox Code Playgroud)
Ste*_*itt 17
这些是简单命令上下文中的变量赋值。正如xhienne所提到的,对于外部命令,它们相当于在命令的持续时间内导出分配的值。
在您的示例中,您使用的是内置命令,因此行为并不完全相同:赋值影响当前环境,但未指定执行内置命令后效果是否持续。要理解您的示例,您需要知道参数扩展发生在处理变量之前;因此与
BAZ=jake echo $BAZ
Run Code Online (Sandbox Code Playgroud)
外壳首先展开$BAZ(导致没有结果),然后设置BAZ为jake,最后运行
echo
Run Code Online (Sandbox Code Playgroud)
它打印一个空行。(然后外壳会BAZ在您的后续echo $BAZ节目中忘记。)
BAZ=jake; echo $BAZ
Run Code Online (Sandbox Code Playgroud)
被解释为两个命令:首先BAZ在当前环境中设置变量,然后echo $BAZ扩展到echo jake并执行。
这里发生了一些关键的事情:
如bash参考手册,简单命令扩展,“如果没有命令名结果,变量赋值影响当前shell环境。否则,变量被添加到执行命令的环境中,不影响当前shell环境。 ” 因此,当您说 时var="something" command arg1 arg2,该命令将var在命令的环境中运行并在command退出后消失。演示很简单 - 从命令中访问命令的环境:
$ BAZ="jake" python -c "import os; print os.environ['BAZ']"
jake
Run Code Online (Sandbox Code Playgroud)
这没什么好惊讶的。这种语法经常用于运行具有修改环境的程序。我的 unix.stackexchange.com 和 askubuntu.com 用户会认出这个例子:如果用户使用德语语言环境,而你只说英语,你可以要求他们重现他们遇到的任何问题并获得英语输出,如下所示:
LC_ALL=C command
Run Code Online (Sandbox Code Playgroud)
另请注意,环境访问并不特定于python. 它可以用C或任何其他编程语言来完成。它恰好是我现在的“首选武器”,仅用于此演示。
变量扩展发生在任何运行之前。因此,当你运行类似的东西时BAZ="foo" echo $BAZ,shell 首先查看它的环境,在那里找不到变量 BAZ,因此$BAZ留空。简单的演示是:
$ BAZ="jake" python -c "import sys; print 'ARG:',sys.argv[1]" $BAZ
ARG:
Traceback (most recent call last):
File "<string>", line 1, in <module>
IndexError: list index out of range
Run Code Online (Sandbox Code Playgroud)还需要注意的是,两者的区别BAZ=jake; echo $BAZ是两个单独的命令语句,这里BAZ=jake将保留在 shell 环境中。用例取决于您的意图。如果您打算运行多个需要此类变量的程序,则可能需要export此类变量。如果您只在这个特定时间需要它,那么前面的变量赋值可能更可取。