如果任何命令返回非零值则中止 shell 脚本

问题描述 投票:0回答:10

我有一个调用许多命令的 Bash shell 脚本。

如果任何命令返回非零值,我希望 shell 脚本自动退出并返回值 1。

这是否可以在不显式检查每个命令的结果的情况下实现?

例如,

dosomething1
if [[ $? -ne 0 ]]; then
    exit 1
fi

dosomething2
if [[ $? -ne 0 ]]; then
    exit 1
fi
linux bash unix shell
10个回答
989
投票

将其添加到脚本的开头:

set -e

如果简单命令以非零退出值退出,这将导致 shell 立即退出。 简单命令是指不属于

if
while
until
测试的一部分,或者不属于
&&
||
列表的任何命令。

有关“set”内部命令的更多详细信息,请参阅 bash 手册

当中间发生某些事情并打破了脚本其余部分的假设时,让脚本顽固地继续下去真的很烦人。 我个人几乎所有的可移植 shell 脚本都是用

set -e
开始的。

如果我专门使用 bash,我将从

开始
set -Eeuo pipefail

这涵盖了以类似方式进行的更多错误处理。 我认为这些是新 bash 程序的合理默认值。 有关这些选项的作用的更多信息,请参阅 bash 手册。


276
投票

添加到已接受的答案:

请记住,

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

例如,假设您有这个脚本

#!/bin/bash
set -e 
./configure  > configure.log
make

...按预期工作:

configure
中的错误会中止执行。

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

#!/bin/bash
set -e 
./configure  | tee configure.log
make

...现在不起作用了。 here对此进行了解释,并提供了解决方法(仅限 Bash):

#!/bin/bash
设置-e 
设置-o管道故障

./配置| tee配置.log
制作

105
投票

示例中的 if 语句是不必要的。 就这样做吧:

dosomething1 || exit 1

如果您采纳 Ville Laurikari 的建议并使用

set -e
那么对于某些命令,您可能需要使用此:

dosomething || true

即使命令失败,

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


30
投票

如果您需要在退出时进行清理,您还可以使用带有伪信号 ERR 的“trap”。这与捕获 INT 或任何其他信号的工作方式相同;如果任何命令以非零值退出,bash 会抛出 ERR:

# 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”,您可能会陷入 EXIT;当脚本因任何原因退出时,你的陷阱将被执行,包括正常结束、中断、-e选项导致的退出等。


18
投票

很少需要

$?
变量。 伪习语
command; if [ $? -eq 0 ]; then X; fi
应始终写为
if command; then X; fi

需要

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

command
case $? in
  (0) X;;
  (1) Y;;
  (2) Z;;
esac

或者当

$?
需要重复使用或以其他方式操作时:

if command; then
  echo "command successful" >&2
else
  ret=$?
  echo "command failed with exit code $ret" >&2
  exit $ret
fi

15
投票

使用顶部的

-e
set -e
运行它。

另请参阅

set -u


10
投票

出现错误时,以下脚本将打印一条带有失败命令的红色错误消息,然后退出。
将其放在 bash 脚本的顶部:

# BASH error handling:
#   exit on command failure
set -e
#   keep track of the last executed command
trap 'LAST_COMMAND=$CURRENT_COMMAND; CURRENT_COMMAND=$BASH_COMMAND' DEBUG
#   on error: print the failed command
trap 'ERROR_CODE=$?; FAILED_COMMAND=$LAST_COMMAND; tput setaf 1; echo "ERROR: command \"$FAILED_COMMAND\" failed with exit code $ERROR_CODE"; tput sgr0;' ERR INT TERM

7
投票
#!/bin/bash -e

应该足够了。


4
投票

类似的表达方式

dosomething1 && dosomething2 && dosomething3
当其中一个命令返回非零值时,

将停止处理。例如,以下命令永远不会打印“done”:

cat nosuchfile && echo "done"
echo $?
1

-3
投票

我只是提出另一个问题以供参考,因为 Mark Edgars 还提出了一个额外的问题,这里有一个额外的示例,涉及整个主题:

[[ `cmd` ]] && echo success_else_silence

这与某人展示的

cmd || exit errcode
相同。

例如,我想确保分区在已安装时被卸载:

[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1
© www.soinside.com 2019 - 2024. All rights reserved.