Bash 在执行脚本的时候,会创建一个新的 shell, 每个 shell 都有自己独立的执行环境,这个环境会有一些默认行为,而这些默认行为可以通过 set
命令来修改。
这里介绍几种常用的 set
命令。
注: set
命令在不带参数执行时,会显示当前 shell 的所有环境变量、函数。
默认情况下, bash 遇到不存在的变量时会忽略。为了让脚本更加严谨和安全,报错并停止执行是一种更好的选择。
1
2
3
| set -u
echo $non_exist_var
|
Output:
1
| bash: line 4: non_exist_var: unbound variable
|
1
2
3
4
| set -x
unameOutput="$(uname -s)"
echo $unameOutput
|
Output:
1
2
3
4
| ++ uname -s
+ unameOutput=Darwin
+ echo Darwin
Darwin
|
默认情况下,脚本执行过程中如果出现运行失败的命令, Bash 会继续执行后面的命令,而这往往是不太安全的行为(因为后面的命令很可能依赖前面命令的成功执行)。
1
2
| cd /non/exist/path
echo "do something dangerous like rm files"
|
Output:
1
2
| bash: line 2: cd: /non/exist/path: No such file or directory
do something dangerous like rm files
|
实践当中,为了避免该问题,我们可以利用逻辑运算符的短路行为来及时终止命令的执行:
1
2
| cd /non/exist/path || { echo "/non/exist/path is not found"; exit 1; }
echo "do something dangerous like rm files"
|
Output:
1
2
| bash: line 2: cd: /non/exist/path: No such file or directory
/non/exist/path is not found
|
这种手工处理的方式比较麻烦,而且容易遗漏。 set -e
命令可以比较好的解决这个问题,该命令设置后,一旦某个命令失败,会立即停止后续命令的执行。
1
2
3
4
| set -e
cd /non/exist/path
echo "do something dangerous like rm files"
|
Output:
1
| bash: line 4: cd: /non/exist/path: No such file or directory
|
set -e
不适用于管道命令,例如:
1
2
3
4
| set -e
cat /non/exist/path | echo hello
echo world
|
Output:
1
2
3
| hello
cat: /non/exist/path: No such file or directory
world
|
set -o pipefail
可以解决该问题:
1
2
3
4
| set -eo pipefail
cat /non/exist/path | echo hello
echo world
|
Output:
1
2
| hello
cat: /non/exist/path: No such file or directory
|
上述四个 set
命令可以按照如下方式一起设置:
1
2
3
4
5
6
| # 写法一
set -euxo pipefail
# 写法二
set -eux
set -o pipefail
|
建议放在所有 Bash 脚本开头。
另外也可以在执行 Bash 脚本时,从命令行传入这些参数:
1
| bash -euxo pipefail /path/to/script.sh
|