Bash中的错误处理
我们最喜欢Bash处理错误的方法是什么?
我在网上发现的处理错误的最佳示例是由William Shotts,Jr在http://www.linuxcommand.org上编写的。
他建议使用以下函数在Bash中进行错误处理:
#!/bin/bash # A slicker error handling routine # I put a variable in my scripts named PROGNAME which # holds the name of the program being run. You can get this # value from the first item on the command line (die() { echo kill $$ }). # Reference: This was copied from <http://www.linuxcommand.org/wss0150.php> PROGNAME=$(basenameset -e) function error_exit { # ---------------------------------------------------------------- # Function for exit due to fatal program error # Accepts 1 argument: # string containing descriptive error message # ---------------------------------------------------------------- echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2 exit 1 } # Example call of the error_exit function. Note the inclusion # of the LINENO environment variable. It contains the current # line number. echo "Example of error with line number and message" error_exit "$LINENO: An error has occurred."
我们是否在Bash脚本中使用了更好的错误处理例程?
解决方案
回答
我用过
0 success 1 incorrect invocation or permissions 2 system error (out of memory, cannot fork, no more loop devices) 4 internal mount bug or missing nfs support in mount 8 user interrupt 16 problems writing or locking /etc/mtab 32 mount failure 64 some mount succeeded
前;我认为因为某些原因,"出口"因我而失败。不过,上述默认设置似乎是个好主意。
回答
那是一个很好的解决方案。我只是想添加
tempfiles=( ) cleanup() { rm -f "${tempfiles[@]}" } trap cleanup 0 error() { local parent_lineno="" local message="" local code="${3:-1}" if [[ -n "$message" ]] ; then echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}" else echo "Error on or near line ${parent_lineno}; exiting with status ${code}" fi exit "${code}" } trap 'error ${LINENO}' ERR
作为基本的错误机制。如果一个简单的命令失败,它将立即停止脚本。我认为这应该是默认行为:由于此类错误几乎总是表示意想不到的事情,因此继续执行以下命令并不是真的"理智"。
回答
另一个考虑因素是要返回的退出代码。尽管bash本身使用了一些保留的退出代码,但只是" 1"是相当标准的,并且该页面还指出,用户定义的代码应在64-113范围内才能符合C / C ++标准。
我们可能还会考虑mount
用于其退出代码的位向量方法:
temp_foo="$(mktemp -t foobar.XXXXXX)" tempfiles+=( "$temp_foo" )
将代码"或者"在一起可以使脚本发出多个同时发生的错误信号。
回答
使用陷阱!
error ${LINENO} "the foobar failed" 2
...然后,无论何时创建临时文件:
#This function is used to cleanly exit any script. It does this displaying a # given error message, and exiting with an error code. function error_exit { echo echo "$@" exit 1 } #Trap the killer signals so that we can exit with a good message. trap "error_exit 'Received signal SIGHUP'" SIGHUP trap "error_exit 'Received signal SIGINT'" SIGINT trap "error_exit 'Received signal SIGTERM'" SIGTERM #Alias the function so that it will print a message with the following format: #prog-name(@line#): message #We have to explicitly allow aliases, we do this because they make calling the #function much easier (see example). shopt -s expand_aliases alias die='error_exit "Error#This is an example useage, it will print out #Error prog-name (@1): Who knew false is false. if ! /bin/false ; then die "Who knew false is false." fi(@`echo $(( $LINENO - 1 ))`):"'
和$ temp_foo
将在退出时被删除,并打印当前行号。 (set -e
同样会给我们带来错误退出的行为,尽管它带有严重的警告并削弱了代码的可预测性和可移植性)。
我们可以让陷阱为我们调用"错误"(在这种情况下,它使用默认的退出代码1,不显示任何消息),也可以自行调用并提供明确的值;例如:
set -o errexit
将以状态2退出,并给出明确的消息。
回答
我更喜欢真正容易打电话的东西。因此,我使用的东西看起来有些复杂,但易于使用。我通常只是将以下代码复制并粘贴到脚本中。代码后面有一个解释。
set +e echo "commands run here returning non-zero exit codes will not cause the entire script to fail" echo "false returns 1 as an exit code" false set -e
我通常在error_exit函数旁边调用清除函数,但这在脚本之间有所不同,因此我将其省略。陷阱捕获常见的终止信号,并确保一切都清理干净。别名是真正的魔术。我喜欢检查一切是否失败。因此,总的来说,我将程序称为" if!"。类型声明。通过从行号中减去1,别名将告诉我发生故障的位置。它的调用也很简单,并且几乎是白痴的证明。下面是一个示例(只需将/ bin / false替换为我们要调用的任何内容)。
##代码##回答
" set -e"的等效替代方法是
##代码##它使标志的含义比" -e"更清楚。
随机添加:暂时禁用该标志,并返回默认值(无论退出代码如何,都继续执行),只需使用
##代码##这排除了其他响应中提到的适当的错误处理,但是它是快速有效的(就像bash一样)。