关于linux:如果任何命令返回非零值,则中止shell脚本?

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脚本。当一个脚本在中间发生故障,并且破坏了脚本其余部分的假设时,让它顽固地继续下去,真的很烦人。


要添加到接受的答案中:

记住,有时set -e是不够的,特别是如果你有管道的话。

例如,假设您有这个脚本

1
2
3
4
#!/bin/bash
set -e
./configure  > configure.log
make

…它按预期工作:configure中的一个错误中止了执行。

明天你会做出一个看似微不足道的改变:

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的建议并使用set -e,那么对于某些命令,您可能需要使用以下命令:

1
dosomething || true

即使命令失败,|| true也会使命令管道具有true返回值,因此-e选项不会终止脚本。


如果您需要在退出时进行清理,也可以将"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选项引起的退出等。


运行时,-eset -e位于顶部。

也可以看看set -u


很少需要$?变量。伪成语command; if [ $? -eq 0 ]; then X; fi应该总是写成if command; then X; fi

需要使用$?的情况是需要对多个值进行检查:

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

这和有人展示的cmd || exit errcode是一样的。

我想确保如果安装了分区,就可以卸载它:

1
[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1