Сценарій 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(вбудована оболонка).
Kusalananda

Ідеально. Хтось захоче перетворити це на відповідь?
Роджер Ліпскомб

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

У 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перенаправляє stdin до /dev/nullкоманд, запущених у фоновому режимі.


Чи працює це тому, що блок коду працює в підпакеті?
Pysis
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.