BashスクリプトにSIGHUPが表示されませんか?

BashスクリプトにSIGHUPが表示されませんか?

次のスクリプトがあります。

#!/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このスクリプトにシグナルを送信するにはどうすればよいですか(必ずしもそうではありません)。

答え1

バッシュマニュアル状態:

Bashがコマンドが完了するのを待ってトラップが確立されたことを知らせると、コマンドが完了するまでトラップは実行されません。

つまり、信号がbash送信されたときに信号が受信されても​​、SIGHUPのトラップはcat信号の終わりにのみ呼び出されます。

この動作が望ましくない場合は、bash組み込み関数(ループ内で+ read)を使用することも、バックグラウンドタスクを使用することもできます(参照)printfcatスティーブンの答え)。

答え2

@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"

ファイル記述子を使用する小さな方法は、stdinがバックグラウンドで開始されたコマンドbashにリダイレクトされることを避けることです。/dev/null

答え3

EXITにトラップがあると、スクリプトは信号を受信したときに外部コマンドが終了するのを待たないことに気づきました。スクリプト例:

$ cat test-trap 
#!/bin/bash
echo "We are $$"
trap "echo 'Trapping EXIT'" EXIT
cat

実行してください:

$ ./test-trap
We are 24814

送信:

$ ./test-trap
We are 24814
# Doing `kill -HUP 24814` in another terminal
Trapping EXIT
Hangup

しかし、混乱した放棄された猫がいるかもしれません。

cat: -: Input/output error

この問題を解決するには、トラップによって呼び出された関数から子プロセスを検索して終了する必要があります。

Ctrl+を押すC

$ ./test-trap
We are 24814
^CTrapping EXIT

Ctrl+のD代わりにCtrl+を押すと、Ccatコマンドは正常に終了します。ただし、スクリプトが終了するとトラップが実行されます。

$ ./test-trap
We are 40183
# I pressed Ctrl+D here...
Trapping EXIT

スクリプトの最後でトラップを取り消すことでこれを防ぐことができます。

#!/bin/bash
echo "We are $$"
trap "echo 'Trapping EXIT'" EXIT
cat
trap - EXIT

EXITをキャッチするさまざまな動作に関するドキュメントが見つかりません。たぶん他の人もそうすることはできませんか?

関連情報