为什么这个Bash脚本没有错误?

时间:2015-12-08 13:36:45

标签: bash

这是我的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块,所以在忽略坏行后,执行会以某种方式恢复到下一个语法正确的行,但是在块结束之后?

我有两个问题:

  1. 发生了什么事?
  2. 将来如何保护自己免受这种行为的影响?

4 个答案:

答案 0 :(得分:15)

  1. if运行命令[,只检查其返回码。 Bash不知道也不关心[命令的语法。

    你可以在那里放一些其他命令,Bash仍然不知道它的特定语法。

  2. 我想到了两件事:

    • 使用[[代替[:Bash 知道并关心语法。

    • 使用ShellCheck 1 ;在线,手动或在您喜欢的编辑器中。

  3. 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将立即退出,但出现以下情况:

     
      
  1. 多命令管道中任何单个命令的失败都不会导致shell退出。只考虑管道本身的故障。

  2.   
  3. 执行后的 直到 后的复合列表时, -e 设置将被忽略/ strong>,或 elif 保留字,以保留字开头的管道,或除最后一个之外的AND-OR列表的任何命令。

  4.   
  5. 如果在忽略-e时,除了subshel​​l命令之外的复合命令的退出状态是失败的结果,则-e不应用于此命令。

  6.         

    此要求分别适用于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关键字后面的列表中命令的退出状态。