Bash 'if' 语句在命令失败时提前退出

Tho*_*nta 9 bash shell-script

以下代码将导致“if”语句提前退出,并且不执行“if”块中的“echo”命令。我想知道为什么这种情况只发生在“if”块中而不是在脚本的主要部分中。注意:我知道将 ':=' 更改为 ':-' 将解决问题 - 我不想解决问题,我希望了解导致问题发生的 'if' 块的执行环境之间的差异首先。

#!/bin/bash

if true; then
        VAR=${$1:='val'}
        echo "This does not run"
fi


VAR=${$1:='val'}
echo "This does run"
Run Code Online (Sandbox Code Playgroud)

输出是

line 4: ${$1:='val'}: bad substitution
line 7: ${$1:='val'}: bad substitution
This does run
Run Code Online (Sandbox Code Playgroud)

再说一遍 - 我对修复错误替换错误消息不感兴趣,我了解如何做到这一点以及为什么会发生这种情况。我想了解的是,为什么echo "This does not run"当“if”块中的上面有一个错误的替换时,该行不会运行。

转载于以下 bash 版本:

GNU bash,版本 5.1.16(1)-release (x86_64-pc-linux-gnu)

GNU bash,版本 4.2.46(2)-release (x86_64-redhat-linux-gnu)

Qua*_*odo 3

正如 Kusalananda 在评论中指出的那样,这本质上与在复合命令中设置 Bash 选项中描述的相同

\n

来自Bash 参考

\n
\n

下面简单描述一下shell\xe2\x80\x99s读取并执行命令时的操作。基本上,shell 执行以下操作:

\n
    \n
  1. 将标记解析为简单命令和复合命令(请参阅 Shell 命令)。

    \n
  2. \n
  3. 执行各种shell 扩展(请参阅 Shell 扩展),将扩展的标记分解为文件名列表(请参阅文件名扩展)以及命令和参数。

    \n
  4. \n
  5. ...

    \n
  6. \n
  7. 执行命令(请参阅执行命令)。

    \n
  8. \n
\n
\n

语句中的块if是一个复合命令,并且存在扩展错误,即VAR=${$1:=\'val\'},因此整个块失败,永远不会到达步骤 6,并且echo永远不会执行第一个。

\n

请注意,这种对扩展错误的特殊处理违反了 POSIX 标准,该标准在第 2.8.1 节中规定扩展错误应退出非交互式 shell

\n

在 POSIX 模式下,Bash 确实以一致的方式运行:

\n
% bash horse \nhorse: line 2: ${$1:=\'val\'}: bad substitution\nhorse: line 4: ${$1:=\'val\'}: bad substitution\nThis does run\n% bash --posix horse \nhorse: line 2: ${$1:=\'val\'}: bad substitution\n
Run Code Online (Sandbox Code Playgroud)\n

为了宣告 Bash 无罪,记录了这种违规行为:

\n
\n

以下列表是当 \xe2\x80\x98POSIX 模式\xe2\x80\x99 生效时,\xe2\x80\x99s 发生的变化:

\n
    \n
  1. 如果在赋值语句后面没有命令名时发生变量赋值错误,则非交互式 shell 将以错误状态退出。
  2. \n
\n
\n