Bash скрипт не видит SIGHUP?


11

У меня есть следующий скрипт:

#!/bin/bash
echo "We are $$"
trap "echo HUP" SIGHUP
cat    # wait indefinitely

Когда я отправляю SIGHUP(использую kill -HUP pid) ничего не происходит.

Если я немного изменю сценарий:

#!/bin/bash
echo "We are $$"
trap "kill -- -$BASHPID" EXIT    # add this
trap "echo HUP" SIGHUP
cat    # wait indefinitely

... тогда скрипт работает echo HUPправильно при выходе (когда я нажимаю Ctrl + C):

roger@roger-pc:~ $ ./hupper.sh 
We are 6233
^CHUP

Что происходит? Как я должен отправить сигнал (это не обязательно должно быть SIGHUP) к этому сценарию?


4
Сигнал будет доставлен, и обработчик сигнала будет выполнен, когда catпроцесс завершится . Попробуйте свой оригинальный сценарий и нажмите, Ctrl+Dчтобы завершить catпроцесс. Пока catпроцесс находится на переднем плане, на HUPсигнал не воздействуют. Попробуйте еще раз с catзаменой на read(встроенная оболочка).
Кусалананда

Отлично. Кто-то хочет превратить это в ответ?
Роджер Липскомб

Я знаю, что это работает таким образом, но я позволю кому-то, у кого есть больше понимания, чем я, почему и почему делает ответ.
Кусалананда

Я использовал while true; do read; doneв конце, иначе ввод текста заставляет его также выйти, и я хочу выйти из него по Ctrl + C.
Роджер Липскомб

Ответы:


21

Руководство Bash гласит:

Если bash ожидает завершения команды и получает сигнал, для которого установлена ​​ловушка, ловушка не будет выполнена, пока команда не завершится.

Это означает, что, несмотря на то, что сигнал получен bashпри его отправке, ваша ловушка на SIGHUP будет вызываться только по catокончании.

Если это поведение нежелательно, то либо используйте bashвстроенные функции (например, read+ printfв цикле вместо cat), либо используйте фоновые задания (см . Ответ Стефана ).


9

@xhienne уже объяснил почему , но если вы хотите, чтобы сигнал действовал сразу (а не выходил из сценария), вы можете изменить свой код на:

#! /bin/bash -
interrupted=true
trap 'interrupted=true; echo HUP' HUP

{ cat <&3 3<&- & pid=$!; } 3<&0

while
  wait "$pid"
  ret=$?
  "$interrupted"
do
  interrupted=false
done
exit "$ret"

Небольшой танец с файловыми дескрипторами - обойти тот факт, что bashперенаправляет стандартный ввод /dev/nullдля команд, запускаемых в фоновом режиме.


Это работает, потому что блок кода работает в подоболочке?
Пизис
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.