我在手册中阅读有关 shell 语法的内容,并发现了以下内容
简单的命令
一个简单的命令是一系列可选变量赋值,后跟空格分隔的单词和重定向,并由控制运算符终止。
所以我决定使用以下脚本进行测试:
#!/usr/bin/bash
if myVar=hello [ "$myVar" ]; then echo "$myVar"; else echo fail "$myVar"; fi
$ ./test.sh
fail
我不明白为什么会失败,如果我对手册的理解是正确的,这应该可行。在 ShellCheck 上尝试此脚本时,我收到以下警告:
SC2097(警告):此分配只能由分叉进程看到。
解释是:
在
中,name=World cmd "$name"
作为环境的一部分传递给name=World
(即,在 execve(2) 的cmd
参数中)。这意味着envp
及其子进程将看到该参数,但其他进程不会。cmd
手册中哪里记录了此行为?没有任何地方说内联赋值(我刚刚提出这个术语)对于它们声明的命令来说是本地的。此外,这并不能解释脚本失败的原因。按照这个逻辑,[ 应该可以访问
myVar
,执行 then 块,并且脚本应该不打印任何内容。
我错过了什么?
请参阅“简单命令扩展”部分。
当执行一个简单的命令时,shell 会执行以下操作 扩展、分配和重定向,从左到右,在 以下顺序。
- 解析器标记为变量赋值的单词(命令名称前面的单词)和重定向将被保存 后期处理。
- 非变量赋值或重定向的单词被扩展(参见 Shell 扩展)。如果扩展后还有剩余的话, 第一个单词被视为命令的名称, 剩下的词是论据。
- 重定向按上述方式执行(请参阅重定向)。
- 每个变量赋值中‘=’后面的文本经过波形符扩展、参数扩展、命令替换、算术运算 扩展,并在分配给变量之前删除引号。
如果没有命令名称结果,则变量分配会影响 当前的 shell 环境。在这样的命令的情况下(一个 仅由赋值语句和重定向组成)、赋值 语句在重定向之前执行。否则,变量 添加到执行命令的环境中并且不影响 当前的 shell 环境。如果任何作业试图 给只读变量赋值,发生错误,并且 命令以非零状态退出。
因此,首先请注意,扩展(包括用
$myVar
的值替换 myVar
)是在执行分配之前完成的。 因此,$myVar
被替换为
myVar
的 previous值,该值是空的。此外,正如我以粗体突出显示的那样,即使执行分配,也仅在执行命令的环境中进行。 因此,它对任何其他命令都不可见,例如
then
或
else
子句中的命令。