
lxterminalターミナルエミュレータウィンドウのbashシェルで、次のコマンドを実行します。
$ trap "echo hello" SIGHUP
$ kill -s HUP $$
hello
$
その後、端末エミュレータウィンドウを閉じます。
ターミナルエミュレータウィンドウを閉じると、SIGHUPは制御プロセス(bashプロセスなど)にのみ送信されますか?
SIGHUPトラップはbashプロセスを終了しないため、bashプロセスは終了しないと予想しましたが、実際にbashプロセスが終了したのはなぜですか?
トラップを(無視)に変更しても""
同じことが起こります。
端末エミュレータが重要です。 xtermウィンドウで実行されているbashで""
xtermウィンドウを閉じることができないようにトラップを設定し、同時にecho hello
xtermウィンドウを閉じるようにトラップを設定します。
ありがとうございます。
答え1
[他の端末エミュレータの実際の可能な動作は無視されます。^D
ウィンドウを閉じてptyで実行されているプロセスに次のものを受け取らせるのではなく、ptyに()を送信するのは完全に合理的な動作です。家庭VEOF
WM_DELETE_WINDOW
SIGHUP
xterm
、この場合はSIGHUP
シェルのプロセスグループに送信します。
あなたが見ている動作は、readline
ライブラリが独自のシグナルハンドラをインストールするために発生します。以下を試してみると:
xterm -e bash --noediting
(またはdash
、zsh
またはksh
代わりにbash --noediting
)次に実行します。
trap 'echo HUP' HUP
端末でウィンドウを閉じることができなくなります。HUP
ウィンドウを強制的に閉じようとすると、シェルがxkill
予想されますEIO
以下は、観測中の動作のより簡単なテストケースで、端末エミュレータは含まれていません。端末で次のコマンドを実行します。
bash --rcfile <(echo 'trap "echo HUP" HUP')
その後、kill -HUP $$
単に印刷されますHUP
。ただし、(sleep 1; kill -HUP $$) &
(またはkill -HUP <pid>
別のウィンドウで)次に起動しないと、シェルは印刷され終了しますexit
(--noediting
= readlineを使用しません)。
readline()
呼び出された関数は、ユーザーbash
入力を待っている間に独自のシグナルハンドラーをインストールし、ユーザー入力を待っている間に戻って元のSIGHUP
ハンドラーを復元します。これはreturnとしてNULL
扱われますEOF
。bash
yy_readline_get()
関数)遅延トラップハンドラを実行する機会がある前に。
答え2
Bashは、読み込む入力が不足しても終了します。これはいくつかの方法で起こり得る。一般的な方法は、シェルスクリプトの最後の行を読むこと、ユーザーがcontrol-Dを入力すること、ターミナルウィンドウを閉じることなどです。
(これを試してみて、bash -i < /dev/null
入力が不足してすぐに終了することを確認することもできます。)
答え3
ため息に加えて、後ろから多くのことが起こっています。たとえば、ターミナルウィンドウを閉じるとptyも閉じるため、すべての出力または入力はI / Oエラーを返します。
ウィンドウが閉じたときにプロセスを実行すると、strace
それを確認できます。bash
bash
プロンプト()で待機しているプロセスから始めて、ウィンドウを閉じますpselect()
。
% strace -p 1090
strace: Process 1090 attached
pselect6(1, [0], NULL, NULL, NULL, {[], 8}) = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=3409, si_uid=500} ---
--- SIGCONT {si_signo=SIGCONT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call)
ioctl(2, TCXONC, TCOON) = -1 EIO (Input/output error)
ioctl(0, TCGETS, 0x7ffe1d1734e0) = -1 EIO (Input/output error)
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = -1 EIO (Input/output error)
bash
ハンドラを処理しようとすると、I / Oエラーが表示され始めます。
この時点で、bashは制御端末がないので終了することを決定し、すべての信号ハンドラを再起動し、自分に別のSIGHUPを送信します。
rt_sigaction(SIGINT, {sa_handler=0x467410, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGTERM, {sa_handler=0x466f10, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGHUP, {sa_handler=0x4640e0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGALRM, {sa_handler=0x4676d0, sa_mask=[HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGWINCH, {sa_handler=0x466f00, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4baaa0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
getpid() = 1090
kill(1090, SIGHUP) = 0
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=1090, si_uid=500} ---
その後、閉じるプロセスが続行されます(再作成.bash_history
など)。
したがって、シェルをシャットダウンすることは、最初のSIGHUPではなく、入力端子を提供するptyの損失です。