一转眼到了2018年3月份,时光穿梭飞快!哎,不感性了,来点理性东西!今天要说下是Bash中的set命令。
set -u
执行脚本的时候,如果遇到不存在的变量,Bash 默认忽略它。而在脚本顶部加上set -u,遇到不存在的变量就会报错,并停止执行。1
2
3
4
5
6
set - u
echo $a
echo bar
上面 $a 是一个未定义的变量,则执行脚本会报错。
-u还有另一种写法-o nounset,两者是等价的。1
set -o nounset
set -x
默认情况下,脚本执行后,屏幕只显示运行结果,没有其他内容。如果多个命令连续执行,它们的运行结果就会连续输出。有时会分不清,某一段内容是什么命令产生的。
set -x用来在运行结果之前,先输出执行的那一行命令。对调试脚本来说非常有用。1
2
3
4
5
set - x
echo bar
执行上面的脚本,结果如下:1
2+echo bar
bar
执行echo bar之前,该命令会先打印出来,行首以+表示。
set -e
之前我们说脚本里有未定义的变量,脚本会默认往下执行。同理如果脚本里面有运行失败的命令(返回值非0),Bash 也会继续执行后面的命令。
那么 set -e 使脚本发生错误就会终止执行。1
2
3
4
5
6
set - e
foo
echo bar
执行结果如下:1
script.sh: 行4: foo: 未找到命令
set -e根据返回值来判断,一个命令是否运行失败。但是,某些命令的非零返回值可能不表示失败,或者开发者希望在命令失败的情况下,脚本继续执行下去。这时可以暂时关闭set -e,该命令执行结束后,再重新打开set -e。1
2
3set + e
command2
set - e
还有一种方法是使用command || true,使得该命令即使执行失败,脚本也不会终止执行。1
2
3
4
5
6
set - e
foo || true
echo bar
set -o pipefail
set -e有一个例外情况,就是不适用于管道命令。
所谓管道命令,就是多个子命令通过管道运算符(|)组合成为一个大的命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e就失效了。
1 |
|
执行结果如下:1
2
3a
script.sh: 行4: foo: 未找到命令
bar
上面代码中,foo是一个不存在的命令,但是foo | echo a这个管道命令会执行成功,导致后面的echo bar会继续执行。
set -o pipefail用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行。1
2
3
4
5
set -eo pipefail
foo | echo a
echo bar
运行后,结果如下:1
2a
script.sh: 行4: foo: 未找到命令
可以看到,echo bar没有执行。
总结
我们通常在bash脚本顶部加上 -eu。1
2
3
set - eu
除了直接在脚本的头部通过set设置外,我们也可以在执行脚本的时候通过传参的形式设置。1
bash - euxo pipefail script.sh