任何命令执行失败时中止 Shell 脚本

linuxopen sourceoperating system更新于 2026/1/27 3:52:17

概述

通过使用 Bash 脚本,我们可以访问强大的编程语言。编写此类脚本可以高效地依次运行多个命令。即使一个命令失败,其他命令仍会执行。

我们将学习如何添加一些保护措施以避免这些错误发生。示例代码已在 Bash 中测试过。它们也适用于其他兼容 POSIX 的 Shell 环境。

问题

首先,让我们来看看 Bash 默认如何处理错误消息。假设我们有一个名为"hello.sh"的简单 shell 脚本,它会打印出单词"Hello",后面跟着单词"World"。

#!/bin/bash
echo hello
echo world

运行该脚本会得到预期结果 -

$ ./hello.sh
hello
world

接下来,我们将添加一条注定会失败的语句。

#!/bin/bash
echo hello
cat non-existing-file
echo world

执行该脚本后,将产生输出。执行不会停止,但仍然会输出"world" -

$ ./hello.sh
hello
cat: non-existing-file: No such file or directory
world

我们的脚本也得到了一个 0 的退出代码,这表明一切顺利。

$ echo $?
0

第一次出错时退出

如果希望脚本中的任何命令失败时都退出,可以使用 set -e 选项。此选项指示脚本在脚本中的任何命令以非零状态退出时立即退出。

以下是如何在 Shell 脚本中使用 set -e 选项的示例 -

#!/bin/bash

# Set the -e option
set -e

# Run some commands
echo "Running command 1"
command1
echo "Running command 2"
command2
echo "Running command 3"
command3

# The script will exit if any of the commands above fail

echo "All commands completed successfully"

在此示例中,如果 command1、command2 或 command3 中的任何命令失败(即以非零状态退出),脚本将立即退出,并且不会执行其余命令。

请注意,set -e 选项仅适用于由 shell 直接运行的命令(例如,echo、command1 等),而不适用于由 shell 扩展运行的命令(例如,$(command))。要使 set -e 选项应用于所有命令(包括由 shell 扩展运行的命令),可以将 set -o pipefail 选项与 set -e 结合使用。

使用 Pipefail

遗憾的是,如果您的脚本包含管道语句,此解决方案将不起作用。例如,如果我们将前两个命令(失败的命令)通过管道连接在一起,从失败的命令开始,就会收到一条错误消息。

#!/bin/bash
set -e
cat non-existing-file | echo hello
echo world

即使我们使用了 set -e,以下命令仍然输出 -

$ ./hello.sh
hello
cat: non-existing-file: No such file or directory
world

如果我们想运行多个命令而不让任何一个命令失败,我们可以在第一个命令中添加 -o pipefail 选项。

#!/bin/bash
set -eo pipefail
cat non-existing-file | echo hello
echo world

我们告诉 bash,如果管道内部发生错误,它应该停止并报告管道中最后一个命令的退出代码。

$ ./hello.sh
hello
cat: non-existing-file: No such file or directory

这会导致我们之前见过的非零返回码 -

$ echo $?
1

结论

我们已经学习了如何使用命令"exit"在发生错误时立即终止shell脚本。我们还添加了 -o pipefail 选项,以便管道的行为与之前相同。请务必在shell脚本的开头添加 set -eo pipeline fail 选项。


相关文章


有用资源