如果任何命令失败,中止Shell脚本
Contents
1.概述
使用Bash 脚本 ,我们拥有了一个强大的工具。Bash 脚本是连续运行多个命令的好方法。在编写脚本的时候,我们要提醒自己,如果一个命令失败了,后面的所有命令仍然会执行。在本文中,我们将学习如何通过添加一些保护措施来防止这种情况。本文示例中使用的命令已经在 Bash 中进行了测试。它们也应该在其他 POSIX 兼容的 shell 中工作。
2. 问题
首先,让我们看一下 bash 脚本在默认情况下是如何处理错误的。假设我们有一个简单的脚本hello.sh打印单词 ‘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
此外,我们的脚本的退出代码为零,表明一切正常:
$ echo $?
0
3. 第一个错误退出
假设我们想让我们的脚本在发生第一个错误时以非零退出代码终止。因此,我们必须在脚本开头使用set 更改 shell 的默认行为:
#!/bin/bash
set -e
echo hello
cat non-existing-file
echo world
在第一行使用 set -e,我们告诉 Bash 在第一个错误时停止执行:
$ ./hello.sh
hello
cat: non-existing-file: No such file or directory
此外,返回的退出代码等于失败命令的退出代码:
$ echo $?
1
4. 使用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
为了处理这种情况,让我们在第一行的set命令中添加*-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