任何命令失败都会中止shell脚本


概述

通过使用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

第一个错误就退出

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

以下是如何在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 pipefail`。

更新于:2023年1月3日

13K+ 浏览量

启动您的职业生涯

完成课程获得认证

开始学习
广告
© . All rights reserved.