bash脚本默认是不做变量检查的,可以所写随用,无需预先定义,未初始化的变量也不会有何提示和报错。这和常见高级的语言不同,因此会带来混乱、不可读、甚至导致不可预期的结果。今天虫虫给大家说说如何开启bash调试选项,提高shell脚本的安全性。主要涉及了-eux和-o pipefail等选项。
bash shell有几个几个内部命令,可以修改shell的行为。我们可以在脚本中通过set来设定-eux和-o pipefail选项,来让bash更易debug,更安全。
-e选项
set -e设置会让bash脚本在有错误时候,立刻退出。该选项极大的改变了bash的默认行为,通常脚本只会忽略失败的命令并继续下一个命令。-e选项可以判断错误,不会对作为条件语句一部分的失败命令作出反应。此外,你还可以使用||附加命令对于那些你不希望失败的命令触发立即退出,类似于Perl中的 or die 语句。
#!/bin/bash
chongchong
echo "hello"
上面的脚本,虫虫是个未知的变量,执行的时候会报"hello.sh: line 3: chongchong: command not found",但是后面的echo语句执行会继续执行,输出"hello"。
如果,语句添加了 set -e,结果就直接抛出错误,不会执行后面的echo语句。
为了防止立即抛出错误,可以后面添加||来将语句编程条件中的一部分,这样就会提示错误,但是不会理解退出。
作为if判断语句,需要在条件语句中也不会立即退出。
上面我们说了set -e的选项。但是,设置-e还远远不够。还需要于配合其他选项一起组合使用。
-E选项
trap用于bash脚本捕获某些信号时触发的代码片段。除了通常的信号(例如SIGINT,SIGTERM,...)之外,trap还可用于捕获特殊的bash信号,如EXIT,DEBUG,RETURN和ERR。在没有-E的情况下使用-e会导致ERR陷阱在某些情况下不会触发。示例代码如下:
可以看到没有按照预期的trap提示错误信息,而是直接抛出了错误。我们加上-E选项再来试试。
如果我们希望ERR trap 在shell函数、命令替换和子shell环境中执行的命令继承,则需要设置-E。在这种情况下,ERRtrap通常不会被继承。
-u选项
set -u选项会将bash shell未设置的变量视为错误并立即退出。使用未设置的变量是导致shell脚本误的常见原因之一,所以,对为设置变量,提示错误并退出很有必要。
上面的脚本中,打印未初始化的变量导致结果打印了了我们不期望
的空行。如果我们使用-u选项(或者脚本中设置set -u)
结果会立即抛出异常"a: unbound variable",未绑定的变量。
为了防止出现该类,错误的出现,我们可以使用${a: -b}来给变量赋个默认值,这样当a为空或未定义时,自动分配默认值b。 默认值设置,不会导致-u的抛出错误退出的行为。
有时你希望在遇到未设置的变量时脚本不会立即退出。比如在if语句中检查变量是否存在。
-o pipefail选项
bash shell通常只查看管道最后一个命令的退出代码。该默认行为通常会有问题,因为它会导致-e选项仅能够对管道的最后一个命令的退出代码起作用。使用-o pipefail特殊选项将管道中非零状态的为最后边退出是的状态代码,换句话说就是如果管道的所有命令都成功退出则设置为零。
不存在的chong命令不会导致立即退出,如将非零退出代码通过|管道,则他的错误代码会被忽略。
设置选项后,不存在的chong命令导致立即抛出错误,下面的命令echo不会再执行。
通过几个以上几个调试选项让bash shell表现得更接近于更高级别的语言。虽然-euo pipefail非常适合早期(类似于高级语言的编译时)发现各种问题,但有时候还不够。下面我们介绍-x选项,它将帮助我们找出你偶尔会遇到的棘手错误。
-x选项
-x选项使bash在执行之前打印每个命令。在做调试bash脚本时,这可以提供很大帮助。请注意,在打印命令之前会自动替换为变量实际值。-x的语句包含执行时存在的实际值!
结果如上图,对于每一条命令会在增加+前缀打印,接着是该命令的执行结果。这就是-x选项。它非常简单,但是在bash代码调试时候非常有用。
本文中虫虫大家介绍了常见的bash调试选项-eux和o pipefail(或set -Eeuxo pipefail),希望可以帮我们提高撰写bash的质量,提高其安全性。如果本文对你有帮助或者有问题,请关注虫虫并留言。