你最喜欢在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 ($0).
# Reference: This was copied from <http://www.linuxcommand.org/wss0150.php>
PROGNAME=$(basename $0)
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脚本中是否有更好的错误处理例程?
不确定这是否对您有帮助,但我修改了这里的一些建议函数,以便在其中包括错误检查(先前命令的退出代码)。
在每次“检查”中,我还将错误的“消息”作为参数传递给日志记录。
#!/bin/bash
error_exit()
{
if [ "$?" != "0" ]; then
log.sh "$1"
exit 1
fi
}
现在要在同一个脚本中调用它(或者在另一个脚本中,如果我使用export -f error_exit),我只需写函数名并传递一个消息作为参数,如下所示:
#!/bin/bash
cd /home/myuser/afolder
error_exit "Unable to switch to folder"
rm *
error_exit "Unable to delete all files"
使用这个,我能够为一些自动化进程创建一个真正健壮的bash文件,它将在错误的情况下停止并通知我(log.sh将这样做)
受本文介绍的思想的启发,我在bash样板项目中开发了一种可读且方便的方法来处理bash脚本中的错误。
通过简单地获取库,你可以得到以下结果(即它会在任何错误时停止执行,就像使用set -e一样,这要感谢ERR上的陷阱和一些bash-fu):
还有一些额外的特性可以帮助处理错误,比如try和catch,或者throw关键字,它们允许您在某个点中断执行以查看回溯。此外,如果终端支持它,它会输出电力线表情符号,为输出的部分颜色以提高可读性,并在代码行上下文中强调导致异常的方法。
缺点是—它不可移植—代码在bash中工作,可能仅>= 4(但我可以想象它可以通过一些努力移植到bash 3)。
为了更好地处理,代码被分离到多个文件中,但我受到了Luca Borrione上面回答的回溯思想的启发。
要阅读更多或查看源代码,请参阅GitHub:
https://github.com/niieani/bash-oo-framework#error-handling-with-exceptions-and-throw
使用陷阱!
tempfiles=( )
cleanup() {
rm -f "${tempfiles[@]}"
}
trap cleanup 0
error() {
local parent_lineno="$1"
local message="$2"
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
...然后,每当你创建一个临时文件:
temp_foo="$(mktemp -t foobar.XXXXXX)"
tempfiles+=( "$temp_foo" )
并且$temp_foo将在退出时被删除,并将打印当前行号。(set -e同样会给你错误退出的行为,尽管它有严重的警告,并削弱了代码的可预测性和可移植性)。
您可以让trap为您调用错误(在这种情况下,它使用默认的退出代码1和无消息)或自己调用它并提供显式值;例如:
error ${LINENO} "the foobar failed" 2
将以状态2退出,并给出一个显式消息。
或者使用-s extdebug,并对陷阱的第一行进行一些修改,以全面地捕获所有非零退出代码(mind set -e非错误非零退出代码):
error() {
local last_exit_status="$?"
local parent_lineno="$1"
local message="${2:-(no message ($last_exit_status))}"
local code="${3:-$last_exit_status}"
# ... continue as above
}
trap 'error ${LINENO}' ERR
shopt -s extdebug
这也与set -eu“兼容”。