我一生都在使用 HPUX/ksh shell,所以现在的 bash 似乎正在提出许多新的方式来做很多事情(其中许多似乎不符合 POSIX 标准 - 例如 'mkdir -p /root/{abc,def,ghi,jkl}' - 显然这是 bash/OpenStack 中的编码指南最佳实践 - 但这完全是另一回事)。
无论如何,我已经在 OpenStack 代码中的多个地方看到了这种脚本的执行:
ENABLE_VCENTER=true bash /root/stack_install.sh
有人能解释一下这是如何工作的吗——我知道 shell 将设置变量,然后调用 shell 脚本(这是 nooB 犯的经典错误,解释了为什么变量赋值不应该带空格——例如 HELLO=world)。但内部究竟发生了什么?
另外,为什么当我尝试这个命令时它似乎对我不起作用:
HELLO=world echo $HELLO
我从 shell 获得以下输出:
[ ubuntuOne : /home/bumblebee ]
> HELLO=world echo $HELLO
[ ubuntuOne : /home/bumblebee ]
>
我在这里遗漏了什么?
谢谢您的回复。
答案1
HELLO=world echo $HELLO
在上述语句中,bash
在执行语句之前进行参数扩展。这意味着$HELLO
在执行语句(包括将 HELLO 设置为world
)之前, 将被替换为空(或 HELLO 的当前值)。
观察:
$ HELLO=world bash -c 'echo $HELLO'
world
请注意,它echo $HELLO
在单引号内。单引号可防止参数扩展。这意味着,直到bash
子 shell 启动并将其视为参数时,才会对 HELLO 进行求值。到那时,HELLO 将被设置为等于world
。
相比之下,请考虑这一行,其中单引号已被双引号替换:
$ HELLO=world bash -c "echo $HELLO"
这里什么都没打印出来,因为双引号不会抑制参数扩展。因此,命令bash
被赋予了两个参数-c
和echo
。因此,什么都没打印出来。
所有血腥细节
man bash
详细解释处理上述命令时发生的情况:
当执行简单命令时,shell 从左到右执行以下扩展、分配和重定向。
1. The words that the parser has marked as variable assignments (those preceding the command name) and redirections are saved for later processing. 2. The words that are not variable assignments or redi‐ rections are expanded. If any words remain after expansion, the first word is taken to be the name of the command and the remaining words are the arguments. 3. Redirections are performed as described above under REDIRECTION. 4. The text after the = in each variable assignment undergoes tilde expansion, parameter expansion, com‐ mand substitution, arithmetic expansion, and quote removal before being assigned to the variable.
再次考虑该命令:
HELLO=world echo $HELLO
参数echo
在步骤 2 中经历了参数扩展,而bash
直到步骤 4 才开始为 HELLO 分配新值。