Таинственный ЛИНЕНО в баш-ловушке ERR - PullRequest
10 голосов
/ 03 августа 2011

Я просто играл с bash, чтобы обойти это летнее полуденное тепло, когда неожиданно получил таинственный результат, для которого я не могу определить его происхождение.

Позвольте мне немного объяснить это.

Я играю с trap 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.

Однако , если I раскомментирует первую ловушку (та, что в 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 - последняя строка в функции прерывания.Может кто-нибудь объяснить простым языком, почему trap возвращает последнюю строку вызываемой функции как строку, которая вызвала ошибку в строке 21 ?

Заранее спасибо!

EDIT

На всякий случай, если кто-то заинтересован в функции отладки.Это производственная версия:

# 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

Ответы [ 2 ]

6 голосов
/ 03 августа 2011

Некоторые важные факты / справочная информация:

  • Ловушки на ERR не наследуются функциями оболочки, даже если они получают остальную среду, если не установлено errtrace.

  • Состояние выхода функции соответствует статусу ее последней команды.

Я предполагаю, что происходит:

В случае, когда обе ловушки активны,

  • Несуществующая команда вызывает ловушку ERR в функции.LINENO - команда несуществующей команды.
  • Ловушка завершает выполнение.Поскольку несуществующая команда была последней командой, возвращаемый статус функции не равен нулю, поэтому срабатывает ловушка ERR в оболочке.LINENO по-прежнему установлен на последнюю строку traperror, поскольку это была последняя строка для выполнения и по-прежнему является текущей строкой, поскольку новая строка еще не была выполнена.

В этом случаегде активна только ловушка оболочки (закомментирована та, что в функции)

  • Несуществующая команда является последней командой в функции, поэтому функция возвращает ненулевое значение, вызывая тем самымERR ловушка оболочки для срабатывания.По той же причине, что и выше, LINENO является последней строкой функции, поскольку это была последняя строка для выполнения и по-прежнему является текущей строкой.
2 голосов
/ 11 февраля 2013

Чтобы убедиться, что в вашей первой версии функции 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...