这是我的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
块,所以在忽略坏行后,执行会以某种方式恢复到下一个语法正确的行,但是在块结束之后?
我有两个问题:
答案 0 :(得分:15)
if
运行命令[
,只检查其返回码。 Bash不知道也不关心[
命令的语法。
你可以在那里放一些其他命令,Bash仍然不知道它的特定语法。
我想到了两件事:
使用[[
代替[
:Bash 知道并关心其语法。
使用ShellCheck 1 ;在线,手动或在您喜欢的编辑器中。
if
和-e
都处理退出代码:如果它非零if
,则会让您进入then
块,并且-e
将退出。你不能同时真正拥有这两种行为。 (嗯,似乎 [
退出时会出现错误结果(1)和语法错误(2)的不同代码,因此可能可能来“检测”语法错误。)
1 或其他一些工具,但这是我所知道的唯一一个。建议欢迎。
答案 1 :(得分:9)
这里没有shell语法错误。
[
命令/ builtin。
set -e
在这里没有帮助的原因是因为显式不是它应该做的事情。如果您的代码中没有set -e
语句,那么if
将变得完全无效。试想一下。
如果您在POSIX spec查看-e
/ errexit
标志的内容,您会看到以下说明:
<强> -e 强>
当此选项打开时,当任何命令失败时(由于Consequences of Shell Errors中列出的任何原因或返回大于零的退出状态),shell将立即退出,但出现以下情况:
多命令管道中任何单个命令的失败都不会导致shell退出。只考虑管道本身的故障。
执行后的 ,直到, 后的复合列表时, -e 设置将被忽略/ strong>,或 elif 保留字,以!保留字开头的管道,或除最后一个之外的AND-OR列表的任何命令。
- 醇>
如果在忽略-e时,除了subshell命令之外的复合命令的退出状态是失败的结果,则-e不应用于此命令。
此要求分别适用于shell环境和每个子shell环境。例如,在:
set -e; (false; echo one) | cat; echo two
见第二点吗?那是你的情况。
shell继续执行的原因是返回&#34;而不是shell语法错误&#34;。您有一个命令错误。 [
命令/ builtin试图解析其参数并失败。然后它返回一个错误返回码。 if
捕获了它,跳过它的主体并返回true(根据if
的记录行为,当没有条件返回true时)。所以shell脚本继续正常。
正如我在评论中指出的那样,如果您使用过[[
(这是一个bash-ism和一个语言结构),那么您的脚本会有语法错误,会在那条线上立即退出(至少在我的测试中)。
答案 2 :(得分:2)
来自bash手册页
-e
如果管道(可能包含一个简单的命令),括在括号中的子shell命令,或作为括号括起来的命令列表的一部分执行的命令之一(参见上面的SHELL GRAMMAR)退出,则立即退出非零状态。如果失败的命令是紧跟在while或者直到关键字后的命令列表的一部分,,那么不会退出 在if或elif保留字后面的部分测试,在&amp;&amp ;;中执行的任何命令的一部分或者││列表,除了最后一个&amp;&amp ;;之后的命令或││,管道中的任何命令,但是最后一个命令,或者命令的返回值是否被反转! ERR上的陷阱(如果已设置)将在shell退出之前执行。此选项分别适用于shell环境和每个子shell环境(请参阅上面的COMMAND EXECUTION ENVIRONMENT),并且可能会导致子shell在执行子shell中的所有命令之前退出。
强调我的。
答案 3 :(得分:1)
首先,这不是语法错误。您只是为[
命令提供了错误的参数。
其次,出于if
选项的目的,将忽略-e
关键字后面的列表中命令的退出状态。