Aborting a shell script if any command returns a non-zero value?
我有一个bash shell脚本,它调用许多命令。如果任何命令返回非零值,我希望shell脚本自动退出,返回值为1。
如果不显式检查每个命令的结果,是否可以这样做?
例如
1 2 3 4 5 6 7 8 9 | dosomething1 if [[ $? -ne 0 ]]; then exit 1 fi dosomething2 if [[ $? -ne 0 ]]; then exit 1 fi |
将此添加到脚本开头:
1 | set -e |
如果一个简单的命令以非零的退出值退出,这将导致shell立即退出。简单命令是不属于if、while或until测试的任何命令,或者是&;&;或列表的一部分。
有关更多详细信息,请参阅"set"内部命令上的bash(1)手册页。
我个人用"set-e"开始几乎所有shell脚本。当一个脚本在中间发生故障,并且破坏了脚本其余部分的假设时,让它顽固地继续下去,真的很烦人。
要添加到接受的答案中:
记住,有时
例如,假设您有这个脚本
1 2 3 4 | #!/bin/bash set -e ./configure > configure.log make |
…它按预期工作:
明天你会做出一个看似微不足道的改变:
1 2 3 4 | #!/bin/bash set -e ./configure | tee configure.log make |
…现在它不起作用了。这里解释了这一点,并提供了一个解决方法(仅限bash):
1 2 3 4 5 6 | #!/bin/bash set -e set -o pipefail ./configure | tee configure.log make |
示例中的if语句是不必要的。就这样做:
1 | dosomething1 || exit 1 |
如果您采纳Ville Laurikari的建议并使用
1 | dosomething || true |
即使命令失败,
如果您需要在退出时进行清理,也可以将"trap"与伪信号err一起使用。这与补漏白int或任何其他信号的工作方式相同;如果任何命令以非零值退出,bash将抛出err:
1 2 3 4 5 6 7 8 9 10 11 | # Create the trap with # trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...] trap"rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM command1 command2 command3 # Partially turn off the trap. trap - ERR # Now a control-C will still cause cleanup, but # a nonzero exit code won't: ps aux | grep blahblahblah |
或者,特别是如果您使用的是"set-e",则可以陷阱退出;然后,当脚本出于任何原因退出时,将执行陷阱,包括正常结束、中断、由-e选项引起的退出等。
运行时,
也可以看看
很少需要
需要使用
1 2 3 4 5 6 | command case $? in (0) X;; (1) Y;; (2) Z;; esac |
或者当
1 2 3 4 5 6 7 | if command; then echo"command successful">&2 else ret=$? echo"command failed with exit code $ret">&2 exit $ret fi |
1 | #!/bin/bash -e |
应该足够了。
像这样的表达
1 | dosomething1 && dosomething2 && dosomething3 |
当其中一个命令返回非零值时将停止处理。例如,以下命令将永远不会打印"完成":
1 2 3 | cat nosuchfile && echo"done" echo $? 1 |
因为有一个额外的问题要标记Edgars的输入,所以只需插入另一个问题作为参考,这里还有一个额外的示例,并涉及到整个主题:
1 | [[ `cmd` ]] && echo success_else_silence |
这和有人展示的
我想确保如果安装了分区,就可以卸载它:
1 | [[ `mount | grep /dev/sda1` ]] && umount /dev/sda1 |