在Ubuntu上,即使设置了-o errexit,bash脚本也总是返回0

时间:2015-05-21 01:37:51

标签: bash ubuntu

我在一个全新的Ubuntu 14.04.2上有一个名为test.sh的脚本,它可以做到这一点:

#!/bin/sh
set -o errexit

# Start by building the box
docker build -t dcyclebox-test .

# Test nginx
docker run dcyclebox-test bash -c 'nginx -v' && echo '[test] nginx works'

echo '[status] end of test script'

nginx命令不存在,所以我希望我在脚本开头设置set -o errexit以使整个脚本返回非零错误代码,但脚本始终返回0:< / p>

$ test.sh 
...
bash: nginx: command not found
[status] end of test script
$ echo $?
0

似乎set -o errexit什么都不做。如果我删除了最后一行,即echo '[status] end of test script',该脚本将按预期返回非零退出代码:

$ test.sh 
...
bash: nginx: command not found
$ echo $?
127

但是如果任何的行失败,我希望脚本失败,而不仅仅是最后一行。我现在唯一能做的就是在每一行的末尾添加&&\,如下所示:

#!/bin/sh

# Start by building the box
docker build -t dcyclebox-test . &&\

# Test nginx
docker run dcyclebox-test bash -c 'nginx -v' && echo '[test] nginx works' &&\

echo '[status] end of test script'

现在,如果nginx不存在,运行脚本将失败(这很好)(请注意我删除了set -o errexit,因为它似乎没有做任何事情。)

$ test.sh 
...
bash: nginx: command not found
$ echo $?
127

所以我的问题是我可以在脚本顶部添加什么命令,如果其中的任何命令以非零代码退出,则告诉它退出?

谢谢!

2 个答案:

答案 0 :(得分:5)

由于你的shebang #!/bin/shsh在Ubuntu上符号链接到dashdash的规则会管理你脚本的执行。

关于set -e及其等价物,set -o errexitman dash州(强调我的):

  

-e errexit如果不是交互式,如果任何未经测试的命令失败,请立即退出。命令的退出状态被认为是显式的                   如果命令用于控制if,elif,while或者直到;或者如果命令是“&amp;&amp;”的左手操作数或                   “||”运算符

根据此定义,您的命令的LHS(左侧)

docker run dcyclebox-test bash -c 'nginx -v' && echo '[test] nginx works'

是一个显式测试的命令,因此在LHS命令失败的情况下自动终止启动。

您可以通过简单地echo '[test] nginx works 单独的命令(显然您也可以将其置于新行)来解决此问题:

docker run dcyclebox-test bash -c 'nginx -v'; echo '[test] nginx works'

现在,如果docker run dcyclebox-test bash -c 'nginx -v'失败(返回非零退出代码),脚本会立即终止(报告退出代码)。

答案 1 :(得分:1)

从手册页:

如果管道(可能包含单个简单命令),列表或复合命令(请参阅上面的SHELL GRAMMAR),则立即退出,并以非零状态退出。 如果失败的命令是紧跟在while或until关键字之后的命令列表的一部分,那么shell不会退出,在if或elif保留字之后的部分测试,在&amp;中执行的任何命令的一部分;&amp; 或||列表除了 final&amp;&amp;&amp; 或||之外的命令,管道中的任何命令但最后一个命令,或者命令的返回值是否被反转!。如果子shell以外的复合命令返回非零状态,因为在忽略-e时命令失败,则shell不会退出。 ERR上的陷阱(如果已设置)将在shell退出之前执行。此选项分别适用于shell环境和每个子shell环境(请参阅上面的COMMAND EXECUTION ENVIRONMENT),并且可能导致子shell在执行子shell中的所有命令之前退出。