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


15

为了安全起见,如果脚本遇到语法错误,我希望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!'

结果(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!
$ 

好吧,我们不能$?在每条语句后检查语法错误。

(我期望从明智的编程语言中获得这样的安全行为……也许这必须作为错误/希望报告给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!'

结果:

$ ./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!
$ 

或许,它是从相关的运动2 http://mywiki.wooledge.org/BashFAQ/105并有事情做与(( ))。但是我发现继续执行语法错误仍然不合理。

不,(( ))没有区别!

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

#!/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!'

结果:

$ ./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!
$ 

set -e还不够,因为语法错误在if语句中。其他任何地方都应该中止脚本。
jordanm

@jordanm好吧,这可以解释为什么set -e没有奏效。但是我的问题仍然有意义。是否有可能因语法错误而中止?
imz –伊万·扎哈拉里舍夫(Ivan Zakharyaschev)2013年

@jordanm删除了“如果”;没有区别(更新了我的问题)。
imz-伊万·扎哈拉里舍夫(Ivan Zakharyaschev)

Answers:


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 "$@"

结果:

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

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


2
现在,您的函数定义已被解析和评估,并且失败了。
13年

不错的解决方案!顺便说一句,在这种情况下,它也不会中止整个程序。我已经echo 'Bad2: has not aborted the execution after bad main!'在您的示例中添加了最后一个,输出为:$ LC_ALL = C ./sh-on-syntax-err ./sh-on-syntax-err:第6行:#:语法错误:应为操作数(错误标记是“#”)Bad2:错误的main后没有终止执行!$
imz – Ivan Zakharyaschev 2013年

但是,我们不应该那么简单地添加一行,而应该将所有内容放入函数中。
imz-伊万·扎哈拉里舍夫(Ivan Zakharyaschev)

@tripleee是的,看起来函数解析失败,所以它不完整,但是在这种情况下,整个程序实际上并未中止(因此,它可能不是错误退出的结果)。
imz-伊万·扎哈拉里舍夫(Ivan Zakharyaschev)

6

您可能会误解的真正含义set -e。仔细阅读help set节目的输出:

-e  Exit immediately if a command exits with a non-zero status.

所以,-e是关于退出状态的命令是非零的,不是在你的脚本语法错误。

通常,使用会被认为是不好的做法set -e,因为所有错误(即,命令返回的所有非零返回值)都应由脚本(应该考虑使用健壮的脚本,而不是在输入带有。空间或以连字符开头)。

根据语法错误的类型,脚本甚至可能根本不执行。我对bash的知识不足,无法准确地判断哪类语法错误(如果只能对它们进行分类)可能导致立即终止脚本。也许一些Bash专家将加入并澄清所有内容。

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

关于您的愿望:

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

答案肯定是不!正如您所观察到的(set -e没有得到您期望的那样),实际上已被很好地记录在案。


我的意思是缺少这样的功能是一个问题。我不想集中精力set -e-仅仅接近我的目标,这就是为什么在这里提到和使用它的原因。我的问题不是关于set -e,而是关于bash的不安全性,如果不能使它在语法错误上中止。我正在寻找一种使其始终在语法错误时中止的方法。
imz-伊万·扎哈拉里谢夫(Ivan Zakharyaschev)

4

您可以通过以下方式使脚本检查自身:

bash -n "$0"

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

我不得不说这并不十分稳健,但是如果它对您有用,那么也许可以接受。


优秀!还是没有 set -ebash -n "$0" || exit
Daniel S

0

首先,(( ))in bash用作算术计算,而不是在if ...中使用 []

其次,这${a[#]}很奇怪,这就是为什么给错误的原因…… #它没有任何数组含义

我不知道你想和这个做什么,但我相信你想知道字段的数量,所以你要${#a[*]}代替

最终,在比较整数时,-eq建议==使用(用于字符串)。在==也将工作,但-eq建议。

所以你要:

if [ ${#a[*]} -eq 2 ]; then 

4
这不是真的。通常将((关键字与关键字一起使用if。例如,if (( 5 * $b > 53 ))。除非你的目标与旧壳的便携性,[[一般可取[

2
是的,我同意@Evan - [[((轻量级的测试与使用专门设计的“如果”等-不像[,他们从来没有产生一个子进程评估条件。
imz-伊万·扎哈拉里舍夫(Ivan Zakharyaschev)

1
[是内置的bash。较旧的shell希望它是自己的程序。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.