背景
有时候在执行shell脚本的时候,在运行/调试的过程中会有些报错看起来不是太明显,那如何高效的调试自己编写的shell脚本呢??
解决方案
网上有一些解决方案,但是尝试了下后觉得使用 shell 中的 set 命令来解决更加方便和快捷。下面来看看 set 命令到底能够有哪些应用场景。
(1)set -u
执行脚本的时候,有时候会遇到变量未定义(如:拼写错误导致变量未定义),Bash 默认是忽略它并且继续执行的,在某些场景这可能会对后面的脚本造成不可预期的错误操作, 所以可以通过 set -u
来控制,具体案例如下:
1 |
|
可以看到,echo $a
输出了一个空行,Bash 忽略了不存在的 $a,然后继续执行 echo bar
。大多数情况下,这不是开发者想要的行为,遇到变量不存在,脚本应该报错,而不是一声不响地往下执行。
通过脚本在头部加上 set -u
后,遇到不存在的变量就会报错,并停止执行。
1 |
|
(2)set -x
在执行复杂脚本的时候,需要对脚本进行类似debug一样的操作,则可以通过设置 set -x
,这样就会对脚本中的执行过程的变量以及具体执行的代码进行输出。
1 |
|
可以看到,在进行条件判断的时候,变量name被具体值替换了,打印了代码走到了条件分支的哪一步,以及打印了相应的有输出的代码行,行首以+表示。这对于调试复杂的脚本是很有用的。
(3)set -e
如果脚本里面有运行失败的命令(返回值非0),Bash 默认会继续执行后面的命令,在实际开发中,这种会导致比较严重的影响。
1 |
|
通过使用 set -e
则可以运行失败的命令就直接退出。
1 |
|
也可以通过下面的方式来指定具体某个代码块运行失败后自动退出。
1 | set -e # 表示打开遇到运行命令返回非0则退出 |
(4)set -o pipefail
set -e
有一个例外情况,就是不适用于管道命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e
就失效了。
1 |
|
上面代码中,foo是一个不存在的命令,但是 foo | echo a
这个管道命令会执行成功,导致后面的 echo bar
会继续执行。
set -eo pipefail
用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本会在该管道执行完后终止执行。
1 |
|
可以看出,管道任务失败后,echo bar则未进行执行。
总结
set命令的上面这四个参数,一般都放在一起使用,常用的两种方式如下:
1 | # 写法一 |