繁体   English   中英

神秘的LINENO在bash陷阱ERR中

[英]Mysterious LINENO in bash trap ERR

我正在玩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

输出是(为了清楚起见,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

所有行号都是正确的 ,第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

如果我取消注释第一个陷阱并注释第二个陷阱,我得到错误在第23行,这也是正确的,因为它是放置错误命令的绝对行。

~$ bash foo.sh 
<---
ERROR: line 23 - command exited with status: 127
--->
foo

所以我的问题是:为什么第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

这适用于:

~$ 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

一些相关的事实/背景信息:

  • 除非设置了errtrace ,否则shell函数不会继承ERR上的陷阱,即使它们获得了其余的环境。

  • 函数的退出状态是其最后一个命令的退出状态。

我猜测发生了什么:

在两个陷阱都处于活动状态的情况下

  • 不存在的命令会触发函数中的ERR陷阱。 LINENO是不存在的命令。
  • 陷阱完成执行。 由于不存在的命令是最后一个命令,因此该函数的返回状态为非零,因此将触发shell中的ERR陷阱。 LINENO仍设置为最后一行traperror因为它是最后一行来执行,仍然是当前行,因为没有新的生产线已尚未执行。

在只有shell陷阱处于活动状态的情况下(函数中的一个被注释掉)

  • 不存在的命令是函数中的最后一个命令,因此使函数返回非零值,从而导致shell的ERR陷阱触发。 出于同样的原因, LINENO是函数的最后一行,因为它是最后一行执行,仍然是当前行。

为了确保在你的traperror函数的第一个版本中ERR信号处理程序不会执行两次,你可以忽略或重置ERR信号处理程序为其程序的其余部分的默认操作 - 在ERR信号处理程序的定义内本身。 这也应该始终为自定义EXIT信号处理程序完成。

trap "" EXIT ERR  # ignore
trap - EXIT ERR   # reset

# for the first version of your traperror function
- trap 'traperror $LINENO ${FUNCNAME}' ERR
- trap 'traperror $LINENO ${FUNCNAME} $BASH_LINENO' ERR
+ trap 'traperror $LINENO ${FUNCNAME}; trap - ERR' ERR
+ trap 'traperror $LINENO ${FUNCNAME} $BASH_LINENO; trap - ERR' ERR

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM