为什么 while 循环中的语法错误会打断脚本(但在 while 循环外部不会)?

3

考虑以下三个 Bash 脚本:

  • 没有语法错误的脚本 - 执行时不会出错,按预期循环输出 "this is the end: -1":
#!/bin/bash

while true ; do
    x=1 # or, read the variable from some external source
    y=2 # or, read the variable from some external source
    z=$(( $x - $y ))
    echo "this is the result: $z"
    sleep 1
done

执行-无限循环,直到我们中断为止:

$ bash test.sh
this is the result: -1
this is the result: -1
this is the result: -1
^C
  • 导致语法错误的脚本(注意缺失的x和y变量,这些变量随后需要用于计算):
#!/bin/bash

while true ; do
    x= # or, read the variable from some external source
    y= # or, read the variable from some external source
    z=$(( $x - $y ))
    echo "this is the result: $z"
    sleep 1
done

执行 - 当出现语法错误时,bash会中断脚本的执行:

$ bash test.sh
test.sh: line 6: -  : syntax error: operand expected (error token is "-  ")

没有while循环的脚本 - 脚本执行不会被中断:
#!/bin/bash

x=
y=
z=$(( $x - $y ))
echo "this is the result: $z"

执行 - bash注意到计算中的语法错误,但不会中断脚本的执行:

$ bash test.sh
test.sh: line 5: -  : syntax error: operand expected (error token is "-  ")
this is the result:

为什么bash在语法错误时在while循环中和不在while循环中会有不同的行为? 编辑:我知道输入变量可以/应该进行验证,并且有各种方法可以做到这一点。我更感兴趣的是为什么它在是否在while循环中表现不同。
1个回答

2
区别不在于它是否在循环中,而在于变量是空的。
$ bash  # start a fresh instance
bash$ x=''
bash$ y=''
bash$ $(( $x - $y ))
bash: -  : syntax error: operand expected (error token is " ")

正如评论中@oguzismail所指出的那样,语法错误实际上并不会导致整个脚本退出;它会导致复合命令(即while循环)中止。你可以在done行后加上echo“still here”来证明这一点。
如果你想在接收外部源的xy时防止发生这种情况,也许可以检查它们是否包含任何非数字字符?
case ${x#-}${y#-} in
  *[!0-9]*)
    echo "$0: error; $x and $y need to be strictly numeric" >&2
    exit 74;;
esac

注意使用 参数扩展 的方法来修剪单个负号(如果存在)的黑客技巧。
正如 @LéaGris 指出的那样,在Bash中,您也可以简单地说“declare -i x y”以使shell将对xy的可能值限制为整数;然后,如果它们接收到无效值,它们将被强制转换为0

第三个片段(没有while循环)也有空变量,但没有被中断。除非我看错了地方? - Tomasz
这看起来像是一个错误。参考手册在 POSIX 模式下指定了这种行为,但您的脚本没有在 POSIX 模式下执行。(“28. 如果算术扩展中的语法错误导致无效表达式,则非交互式 shell 会退出。”) - tripleee
2
不是一个 bug。在 Bash 中,Shell 错误会终止所有复合命令。如果你在 while 循环后面加上 echo x,你会发现脚本没有被中断。 - oguz ismail
1
@tripleee 如果使用bash,请不要错过使用变量的“i”标志来保护整数数字的替代方法:declare -i x y - Léa Gris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接