这是我的Bash脚本:
#!/bin/bash -e if [ == "" ]; then echo "BAD" exit 1 fi echo "OK"
这是输出:
./test.sh: line 3: [: ==: unary operator expected OK
返回码为0.
在第3行有一个明显的语法错误.而不是提出语法错误并拒绝运行脚本,不知何故脚本运行并在运行时报告语法错误.该-e
标志并未保护我 - 显然if
语句中的语法错误构成错误条件而不是立即退出程序的理由.但是,不知怎的,Bash 已经解析了整个if ... fi
块,所以在忽略坏线之后,执行会以某种方式恢复,而不是在下一个语法正确的行但是在块结束之后?
我有两个问题:
到底是怎么回事?
我将来如何保护自己免受这种行为的影响?
Biffen.. 15
if
运行命令[
,只检查其返回码.Bash不知道也不关心[
命令的语法.
你可以在那里放一些其他的命令,Bash仍然不会知道它的特定语法.
我想到两件事:
使用[[
而不是[
:Bash 确实知道并关心它的语法.
使用ShellCheck 1 ; 在线,手动或在您喜欢的编辑器中.
双方if
并-e
处理退出代码:如果是非零if
不会让你变成then
块,并且-e
将退出.你不可能同时拥有这两种行为.(嗯,这似乎 [
退出提供虚假结果(1)和语法错误(2)不同的代码,所以它可能是有可能为"检测"语法错误.)
1或其他一些工具,但这是我所知道的唯一一个.建议欢迎.
if
运行命令[
,只检查其返回码.Bash不知道也不关心[
命令的语法.
你可以在那里放一些其他的命令,Bash仍然不会知道它的特定语法.
我想到两件事:
使用[[
而不是[
:Bash 确实知道并关心它的语法.
使用ShellCheck 1 ; 在线,手动或在您喜欢的编辑器中.
双方if
并-e
处理退出代码:如果是非零if
不会让你变成then
块,并且-e
将退出.你不可能同时拥有这两种行为.(嗯,这似乎 [
退出提供虚假结果(1)和语法错误(2)不同的代码,所以它可能是有可能为"检测"语法错误.)
1或其他一些工具,但这是我所知道的唯一一个.建议欢迎.
这里没有shell语法错误.
[
命令/ builtin 的参数中有错误.
set -e
这里没有帮助的原因是因为那显然不是它应该做的.如果您的代码中没有语句,那set -e
将变得完全没用if
.试想一下.
如果您在POSIX规范中查看-e
/ errexit
flag的内容,您会看到以下描述:
-e
当此选项打开时,当任何命令失败时(由于Shell错误的后果中列出的任何原因或返回大于零的退出状态),shell将立即退出并出现以下异常:
多命令管道中任何单个命令的失败都不会导致shell退出.只考虑管道本身的故障.
该-e设置应执行以下化合物列表时,可以忽略不计,同时,直到,如果,或ELIF保留字,管道开始用!保留字,或除最后一个之外的AND-OR列表的任何命令.
如果除了子shell命令之外的复合命令的退出状态是在忽略-e时失败的结果,则-e不应用于此命令.
此要求分别适用于shell环境和每个子shell环境.例如,在:
set -e; (false; echo one) | cat; echo two
看点二吗?那是你的情况.
shell继续执行的原因是"不是shell语法错误".您有一个命令错误.该[
命令/内建试图解析它的参数和失败.然后它返回一个错误返回码.该if
抓的是,跳过它的身体并返回true(按照中记录的行为if
时,没有条件返回true).所以shell脚本继续正常.
然而,正如我在评论中指出的那样,如果你曾经使用过[[
(这是一个bash-ism和一个语言结构)那么你的脚本会出现语法错误并且会立即退出该行(至少在我的测试中).