这个 shell/Bash 语法是什么:someVariable=someValue someCommand

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(导致没有结果),然后设置BAZjake,最后运行

 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并执行。


Ser*_*nyy 5

这里发生了一些关键的事情:

  • 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此类变量。如果您只在这个特定时间需要它,那么前面的变量赋值可能更可取。