Проблема с синтаксисом ловушки в bash

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

#!/bin/bash

set -e

function handle_error {
    umount /mnt/chroot
    losetup -d $LOOP_DEV1 $LOOP_DEV2
}

trap "{ echo \"$BASH_COMMAND failed with status code $?\"; handle_error; }" ERR

Видит ли кто-нибудь проблему с написанием ловушки? В случае ошибки ловушка выполняется нормально, но также выдает другое нежелательное сообщение об ошибке ниже.

/root/myscript.sh: line 60: } ERR with status code 0: command not found
##line 60 is that line of code that exited with a non zero status

Как мне написать это правильно, чтобы не было сообщения об ошибке? А что, если бы мне пришлось отправить аргументы $ LOOP_DEV1 и $ LOOP_DEV2 из основного скрипта в ловушку, а затем в функцию handle_error? Прямо сейчас они экспортируются как переменные среды в основной скрипт. Я поискал примеры ловушек, но ничего похожего не нашел.

ИЗМЕНИТЬ

Я изменил шебанг с / bin / sh на / bin / bash. Поскольку / bin / sh уже был привязан к bash, я не ожидал единорогов и не видел их.


person The Governor    schedule 13.07.2013    source источник
comment
Если ваш сценарий фактически выполняется с sh, а не с bash, вам необходимо определить функцию с handle_error () {. Ключевое слово function - это расширение bash.   -  person chepner    schedule 13.07.2013
comment
@chepner В большинстве случаев / bin / sh не является символьной ссылкой на bash? По крайней мере, так в моей системе.   -  person The Governor    schedule 13.07.2013
comment
Если вы используете синтаксис Bash, тогда вы должны указать #!/bin/bash в строке shbang, даже если окажется, что /bin/sh является символической ссылкой на /bin/bash. Таким образом, если ваш сценарий когда-либо запускается в системе, где /bin/sh не символическая ссылка на /bin/bash, он все равно будет работать правильно.   -  person Adam Rosenfield    schedule 13.07.2013
comment
Кроме того, некоторые функции могут быть отключены, если bash запущен под именем /bin/sh, хотя, похоже, здесь это не так.   -  person chepner    schedule 14.07.2013


Ответы (1)


Этот вызов прерывания создает интересную рекурсию, потому что $BASH_COMMAND$?) раскрываются при выполнении команды trap. Однако $BASH_COMMAND в этот момент является самой командой прерывания, включая текст $BASH_COMMAND (а также некоторые кавычки и точки с запятой). На самом деле выяснить, какая команда должна выполняться при срабатывании ловушки, - интересное исследование, но нет необходимости устранять проблему, что вы можете сделать следующим образом:

trap '{ echo "$BASH_COMMAND failed with status code $?"; handle_error; }' ERR

Обратите внимание, что замена " на ' не только позволяет избежать немедленного расширения параметров, но и позволяет избежать необходимости экранирования внутренних ".

person rici    schedule 14.07.2013
comment
Кажется, работает. Большое спасибо. Отправлю, если я выясню команду, которая пытается выполнить в результате рекурсии. - person The Governor; 15.07.2013
comment
@braindead: вы можете обмануть, просто набрав trap и посмотрев, что такое команда, связанная с ERR, хотя вам нужно внимательно смотреть на кавычки. Вы увидите, что он дважды вызывает handle_error, но между двумя вызовами он пытается выполнить "} ERR failed with status code 0", что приводит к отображаемому вами сообщению об ошибке. Помните, что { и } не являются саморазграничивающими символами; Я переместил " выше, чтобы было более очевидно, что происходит, хотя не имеет значения, находится ли " до или после }. - person rici; 15.07.2013