如何让 bash 在语法错误时中止脚本的执行?

imz*_*hev 16 bash shell-script error-handling

为了安全起见,如果遇到语法错误,我希望 bash 中止脚本的执行。

令我惊讶的是,我无法做到这一点。(set -e还不够。)示例:

#!/bin/bash

# Do exit on any error:
set -e

readonly a=(1 2)

# A syntax error is here:

if (( "${a[#]}" == 2 )); then
    echo ok
else
    echo not ok
fi

echo status $?

echo 'Bad: has not aborted execution on syntax error!'
Run Code Online (Sandbox Code Playgroud)

结果(bash-3.2.39 或 bash-3.2.51):

$ ./sh-on-syntax-err
./sh-on-syntax-err: line 10: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 
Run Code Online (Sandbox Code Playgroud)

好吧,我们不能$?在每个语句之后检查以捕获语法错误。

(我期望从一种明智的编程语言中获得这种安全的行为......也许这必须作为一个错误/希望报告给 bash 开发人员)

更多实验

if 没什么区别。

删除if

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
(( "${a[#]}" == 2 ))
echo status $?
echo 'Bad: has not aborted execution on syntax error!'
Run Code Online (Sandbox Code Playgroud)

结果:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 
Run Code Online (Sandbox Code Playgroud)

也许,它与http://mywiki.wooledge.org/BashFAQ/105 中的练习 2 相关,并且与(( )). 但我发现在语法错误后继续执行仍然不合理。

不,(( ))没有区别!

即使没有算术测试,它的表现也很糟糕!只是一个简单的基本脚本:

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
echo "${a[#]}"
echo status $?
echo 'Bad: has not aborted execution on syntax error!'
Run Code Online (Sandbox Code Playgroud)

结果:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 
Run Code Online (Sandbox Code Playgroud)

ahi*_*end 9

将整个包装成一个函数似乎可以解决问题:

#!/bin/bash -e

main () {
readonly a=(1 2)
    # A syntax error is here:
    if (( "${a[#]}" == 2 )); then
        echo ok
    else
        echo not ok
    fi
    echo status $?
    echo 'Bad: has not aborted execution on syntax error!'
}

main "$@"
Run Code Online (Sandbox Code Playgroud)

结果:

$ ./sh-on-syntax-err 
$ ./sh-on-syntax-err line 6: #: syntax error: operand expected (error token is "#")
$ 
Run Code Online (Sandbox Code Playgroud)

虽然我不知道为什么 - 也许其他人可以解释?

  • 现在你的函数定义被解析和评估,但它失败了。 (2认同)

gni*_*urf 6

您可能对 的真正含义产生了误导set -e。仔细阅读help set节目的输出:

-e  Exit immediately if a command exits with a non-zero status.
Run Code Online (Sandbox Code Playgroud)

非零命令-e的退出状态也是如此,而不是脚本中的语法错误。

一般来说,使用 被认为是不好的做法set -e,因为所有错误(即命令的所有非零返回)都应该由脚本巧妙地处理(想想强大的脚本,而不是那些在您输入带有空格或以连字符开头)。

根据语法错误的类型,脚本甚至可能根本不会执行。我对 bash 的了解不够,无法确切说明哪类语法错误(如果可以分类的话)可能会导致脚本立即中止。也许一些 Bash 大师会加入并澄清一切。

我只希望我澄清了set -e声明!

关于你的愿望:

我期望从一种明智的编程语言中获得这种安全的行为......也许这必须作为一个错误/愿望报告给 bash 开发人员

答案肯定是否定的!正如您所观察到的(set -e没有您所期望的响应)实际上有很好的记录。

  • 我的意思是缺乏这样的功能是一个问题。我不想专注于“set -e”——它只是有点接近我的目标,这就是这里提到和使用它的原因。我的问题不是关于“set -e”,而是关于 bash 如果不能在语法错误时中止的不安全性。我正在寻找一种方法让它总是在语法错误时中止。 (3认同)

tri*_*eee 5

你可以通过放置类似的东西来让脚本自我检查

bash -n "$0"
Run Code Online (Sandbox Code Playgroud)

在脚本顶部附近——set -e在任何重要代码段之后但之前。

我不得不说这感觉不是很健壮,但如果它对你有用,也许它是可以接受的。