TL; DR:对于export FOO=bar,bash调用其临时环境创建,FOO=bar在该环境中进行设置,然后产生的最终命令export FOO。在这一点上,FOO作为最后一个参数。
啊,被滥用的$_:
($ _,下划线。)在shell启动时,设置为用于调用在环境或参数列表中传递的正在执行的shell或shell脚本的绝对路径名。随后,在扩展后,扩展到上一个命令的最后一个参数。还设置为用于调用每个执行的命令的完整路径名,并将其放置在导出到该命令的环境中。检查邮件时,此参数保存邮件文件的名称。
让我们看一些变化:
$ man; echo $_
What manual page do you want?
man
$ man foo; echo $_
No manual entry for foo
foo
$ echo; echo $_
echo
$ echo bar foo; echo $_
bar foo
foo
$ foo=x eval 'echo $foo'; echo $_
x
echo $foo
$ bar() { man $1; }; echo $_
foo
$ for (( i=0; $i<0; i=i+1 )); do echo $i; done; echo $_
foo
$ bar; echo $_
What manual page do you want?
man
$ bar foo; echo $_
No manual entry for foo
foo
$ MANPATH=/tmp; echo $_
$ export MANPATH=/tmp; echo $_
MANPATH
因此,我们在这里看到三种模式:
- 从文件系统,函数和内置函数调用的命令的行为与通常预期的一样:
$_如果没有参数,则设置为命令名称本身,否则设置为最后出现的参数。
- 在函数定义,循环和其他逻辑构造之后:
$_不会被修改。
- 其他一切:
$_设置为不太期望的值;奇怪的。
我已经对代码进行了检测,以提供一些有关怪异的见解。
$ ./bash --noprofile --norc -c 'man foo'
lastword=[man]
lastarg=[foo]
$ ./bash --noprofile --norc -c 'export FOO=bar'
lastword=[export]
lastarg=[FOO=bar]
bind_variable, name=[FOO], value=[bar]
before bind_lastarg, lastarg=[FOO]
bind_lastarg, arg=[FOO]
bind_variable, name=[_], value=[FOO]
$ ./bash --noprofile --norc -c 'declare FOO=bar'
lastword=[declare]
lastarg=[FOO=bar]
bind_variable, name=[FOO], value=[(null)]
before bind_lastarg, lastarg=[FOO=bar]
bind_lastarg, arg=[FOO=bar]
bind_variable, name=[_], value=[FOO=bar]
您可以看到在所有情况下解析器都可以看到预期的最后一个参数(lastarg=),但是此后发生的情况取决于bash认为应该发生的情况。请参阅execute_cmd.c,execute_simple_command()。
对于export FOO=bar,bash进行赋值,然后导出变量。这似乎与文档的主张(即扩展后计算的最后一个参数)一致。
EDITOR是出口的论点