我正在玩bash来绕过这个夏天的下午炎热,突然间我有一个神秘的结果,我无法确定它的起源.
让我解释一下.
我正在使用陷阱ERR来为我的bash脚本创建一些调试功能.
这是运行良好的脚本:
traperror () {
local err=$? # error status
local line=$1 # LINENO
[ "$2" != "" ] && local funcstack=$2 # funcname
[ "$3" != "" ] && local linecallfunc=$3 # line where func was called
echo "<---"
echo "ERROR: line $line - command exited with status: $err"
if [ "$funcstack" != "" ]; then
echo -n " ... Error at function ${funcstack[0]}() "
if [ "$linecallfunc" != "" ]; then
echo -n "called at line $3"
fi
echo
fi
echo "--->"
}
#trap 'traperror $LINENO ${FUNCNAME}' ERR
somefunction () {
trap 'traperror $LINENO ${FUNCNAME} $BASH_LINENO' ERR
asdfas
}
somefunction
echo foo
Run Code Online (Sandbox Code Playgroud)
输出是(stderr /dev/null
为了清楚起见; bash错误当然foo.sh: line 23: asdfas: command not found
是你知道错误代码127)
~$ bash foo.sh 2> /dev/null
<---
ERROR: line 21 - command exited with status: 127
... Error at function somefunction() called at line 24
--->
foo
Run Code Online (Sandbox Code Playgroud)
所有行号都是正确的,第21行是启动函数"somefunction"的地方,第24行是调用它的地方.
但是如果我取消注释第一个陷阱(main中的那个),我得到这个输出:
~$ bash foo.sh 2> /dev/null
<---
ERROR: line 21 - command exited with status: 127
... Error at function somefunction() called at line 24
--->
<---
ERROR: line 15 - command exited with status: 127
--->
foo
Run Code Online (Sandbox Code Playgroud)
如果我取消注释第一个陷阱并注释第二个陷阱,我得到的错误是第23行,这也是正确的,因为它是放置错误命令的绝对行.
~$ bash foo.sh
<---
ERROR: line 23 - command exited with status: 127
--->
foo
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:为什么第15行呢?该行号来自哪里?第15行是陷阱功能的最后一行.任何人都可以用简单的英语解释为什么陷阱返回它所调用的函数的最后一行作为第21行产生错误的行?
提前致谢!
编辑
以防万一有人对调试功能感兴趣.这是生产版本:
# Copyright (c): Hilario J. Montoliu <hmontoliu@gmail.com>
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
set -o errtrace
trap 'traperror $? $LINENO $BASH_LINENO "$BASH_COMMAND" $(printf "::%s" ${FUNCNAME[@]})' ERR
traperror () {
local err=$1 # error status
local line=$2 # LINENO
local linecallfunc=$3
local command="$4"
local funcstack="$5"
echo "<---"
echo "ERROR: line $line - command '$command' exited with status: $err"
if [ "$funcstack" != "::" ]; then
echo -n " ... Error at ${funcstack} "
if [ "$linecallfunc" != "" ]; then
echo -n "called at line $linecallfunc"
fi
else
echo -n " ... internal debug info from function ${FUNCNAME} (line $linecallfunc)"
fi
echo
echo "--->"
}
somefunction () {
asdfasdf param1
}
somefunction
echo foo
Run Code Online (Sandbox Code Playgroud)
这适用于:
~$ bash foo.sh 2> /dev/null
<---
ERROR: line 26 - command 'asdfasdf param1' exited with status: 127
... Error at ::somefunction::main called at line 29
--->
<---
ERROR: line 22 - command 'asdfasdf param1' exited with status: 127
... internal debug info from function traperror (line 0)
--->
foo
Run Code Online (Sandbox Code Playgroud)
一些相关的事实/背景信息:
ERR
除非errtrace
已设置,否则陷阱打开不会被shell函数继承,即使它们获得了其余的环境.
函数的退出状态是其最后一个命令的退出状态.
我猜测发生了什么:
在两个陷阱都处于活动状态的情况下
ERR
函数中的陷阱.LINENO
是不存在的命令.ERR
触发了shell中的陷阱. LINENO
仍然设置为最后一行,traperror
因为它是最后一行,仍然是当前行,因为还没有新行执行.在只有shell陷阱处于活动状态的情况下(函数中的一个被注释掉)
ERR
陷阱触发.出于同样的原因,这LINENO
是函数的最后一行,因为它是最后一行,仍然是当前行. 归档时间: |
|
查看次数: |
4415 次 |
最近记录: |