Много примеров для trap
использования trap ... INT TERM EXIT
в задачах очистки. Но действительно ли необходимо перечислять все три сигсипа?
В руководстве сказано:
Если SIGNAL_SPEC - EXIT (0), ARG выполняется при выходе из оболочки.
что, я считаю, применимо независимо от того, закончился ли скрипт нормально или он закончился, потому что получил SIGINT
или SIGTERM
. Эксперимент также подтверждает мою веру:
$ cat ./trap-exit
#!/bin/bash
trap 'echo TRAP' EXIT
sleep 3
$ ./trap-exit & sleep 1; kill -INT %1
[1] 759
TRAP
[1]+ Interrupt ./trap-exit
$ ./trap-exit & sleep 1; kill -TERM %1
[1] 773
TRAP
[1]+ Terminated ./trap-exit
Тогда почему так много примеров перечисляют все INT TERM EXIT
? Или я что-то пропустил и есть ли случай, когда подошва EXIT
пропустит?
INT TERM EXIT
код очистки, выполняется дважды, когдаSIGTERM
илиSIGINT
получен.Ответы:
Спецификация POSIX не говорит много об условиях, приводящих к выполнению ловушки EXIT, а только о том, как должна выглядеть ее среда при выполнении.
В пепельном корпусе Busybox ваш тест выхода-ловушки не повторяет «TRAP» перед выходом из-за SIGINT или SIGTERM. Я подозреваю, что существуют другие оболочки, которые могут работать не так.
источник
dash
также не заманивает в ловушку только,EXIT
когда это получаетSIGINT/SIGTERM
.zsh
также - возможно,bash
это единственная оболочка, гдеEXIT
также совпадают сигналы.zsh
не ловит ,EXIT
когда получаетINT
, но делает, когда получаетTERM
. РЕДАКТИРОВАТЬ: я только заметил, сколько лет это было ...Да, есть разница.
Этот скрипт завершится, когда вы нажмете Enter, или отправите его
SIGINT
илиSIGTERM
:Этот скрипт завершится, когда вы нажмете Enter:
* Проверено в sh , Bash и Zsh . (больше не работает в sh при добавлении команды для запуска trap)
Есть также то, что сказал @Shawn: Эш и Дэш не улавливают сигналы
EXIT
.Таким образом, для надежной обработки сигналов лучше всего избегать перехватов
EXIT
и использовать что-то вроде этого:источник
mktemp
вызовами.exit
необходимо вcleanup
?ERR
чтобы справиться с этим, но он не переносим .trap - INT TERM; kill -2 $$
качестве последней строки очистки вы захотите сообщить родительской оболочке о преждевременном выходе из нее. Если родительская оболочка foobar.sh вызывает ваш скрипт (foo.sh), а затем вызывает bar.sh, вы не хотите, чтобы bar.sh выполнялся, если INT / TERM отправляется на ваш foo.sh.trap cleanup EXIT
будет обрабатывать это распространение автоматически, поэтому IMO является самым надежным. Это также означает, что вам не придется звонитьcleanup
в конце сценария.Уточнение последнего ответа, потому что у него есть проблемы:
Очки выше:
Обработчики INT и TERM не закрываются для меня, когда я тестирую - они обрабатывают ошибку, затем оболочка возвращается к выходу (и это не так уж удивительно). Поэтому я гарантирую, что очистка завершается позже, и в случае сигналов всегда используется код ошибки (а в другом случае нормального выхода сохраняет код ошибки).
В bash кажется, что выход из обработчика INT также вызывает обработчик EXIT, поэтому я освобождаю обработчик выхода и вызываю его сам (который будет работать в любой оболочке независимо от поведения).
Я перехватываю выход, потому что сценарии оболочки могут выйти до того, как они достигнут дна - синтаксические ошибки, set -e и ненулевой возврат, просто вызывая выход. Вы не можете полагаться на шеллскрипт, добирающийся до основания.
SIGQUIT это Ctrl- \, если вы никогда не пробовали. Получает бонусный coredump. Поэтому я думаю, что это также стоит отловить, даже если это немного неясно.
Прошлый опыт говорит, что если вы (как и я) всегда нажимаете Ctrl-C несколько раз, вы иногда будете ловить его наполовину через часть очистки сценария оболочки, так что это работает, но не всегда так идеально, как вам бы хотелось.
источник
trap
вызывающему получит 130 для SIGINT, 143 для SIGTERM и т.д. Так что я бы захватить и передать правильный код выхода , как:sig_cleanup() { err=$?; trap '' EXIT; (exit $err); cleanup; }
.trap '' EXIT INT TERM
функции очистки? Это чтобы предотвратить случайное прерывание пользователем очистки, о котором вы упоминали в предыдущем абзаце? Разве это неEXIT
избыточно?