私の落とし穴がうまくいかないのはなぜですか?

私の落とし穴がうまくいかないのはなぜですか?

echoSIGSTOPまたは、信号が受信されたときに応答するスクリプトが提供されますSIGHUP

$cat test.sh 
function clean_up {
    echo "cleaning up!"
}

echo 'starting!'

trap clean_up SIGSTOP SIGHUP

sleep 100

私はそれをバックグラウンドで実行します:

$./test.sh > output &
[4] 42624

その後、-1つまりを使って殺しました。ため息をつく

$kill -1 42624

しかし、trap期待どおりに動作しません。つまり、outputファイルに内容がありませんcleaning up!

$cat output 
starting!

どうしたの?

答え1

これマニュアルページbash状態

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

あなたの例では、trap完了するまで実行されません。sleep 100

答え2

実際には印刷されますが、結果を見るには100秒待つ必要があります。

あなたは言う:

$./test.sh > output &
[4] 42624

確認すると、ps aux次のような結果が表示されます。

xiaobai  42624  0.0  0.1 118788  5492 pts/3    S    04:07   0:00 /bin/bash
xiaobai  42626  0.0  0.0 108192   668 pts/3    S    04:07   0:00 sleep 100

デフォルトのスクリプトプロセス/bin/bash、PID 42624はまだスリープ100が完了するのを待っています。メインプロセスがシグナル1を受信して​​も、タスクをsleep 100実行する前に完了するまで待つ必要がありますecho "cleaning up!"。つまり、 。

睡眠プロセスをバックグラウンドプロセスにすることができます。この場合、スクリプトecho "cleaning up!"プロセスが終了していない場合にのみ、スクリプトプロセスが待たずに実行される可能性があります。sleep process

次のスクリプトを使用して、概念(つまり、スクリプトがシグナルをsleep処理する前に待機)を実演できます。

function clean_up {
    echo "cleaning up!"
}

echo 'starting!'

trap clean_up SIGHUP
sleep 5000 &
echo 1
sleep 20
echo 2
sleep 10
echo 3

通常どおりこのスクリプトを実行し、./test.sh > outputPIDが23311であることをps aux確認して実行します。また、このステップに注意してください。つまり、スクリプトがecho 1と入力するとsendを送信し、2が出るのを待ちます。その「整理」はすでに2に記載されています。以前一緒に印刷されました。最後にスクリプトを終了する順番です。/bin/bashkill -1 23311cat outputsleep 20kill -1 23311echo 3

$ cat output                                                                                            
starting!
1
cleaning up!
2
3
$ 

上記の実験は、スクリプトがSIGHUP信号を受信し、バックグラウンドプロセスを待たずに、前のすべての前景プロセスが完了した後にシグナルハンドラを実行することを証明しています。

話が面白くなるのに、元の台本でこうすればどうだろうかkill -1 PID_of_sleep_100

スリーププロセスは SIGHUP をスクリプトプロセスに返さないため、印刷せずにすべてのプロセスを終了します。

したがって、あなたの仕事のための解決策があります。kill -1 PPIDスクリプトプロセスのSIGHUPを承認するには、(スクリプトプロセス)を実行してからkill -1 PID(休止プロセス)を実行できます.スクリプトプロセスは終了前にSIGHUPハンドラを実行します。楽しいハッキングになりますように:)

すべての信号が同じというわけではありません。SIGKILLはトラップを許可しません。。 -9スクリプトプロセスを終了すると、スリーププロセスは引き続き実行され、対応する親PIDは1になります(検査に合格ps -ef)。

[修正する]:

一般的にkill -N script_PIDそうです。信号 N がスクリプトに取り込まれない場合は、単にスクリプトを終了します。。ただし、SIGINTに注意してください。kill -2 script_PIDスクリプトがそれをキャプチャできなくても、直接終了するわけではありません。スクリプトは、子プロセス(sleep 10など)が完了するのを待ちます。ここで、script_PIDで複数のシャットダウン(kill -2 script_PIDANDなど)を実行するとしますkill -user-defined_trap_N script_PID

  1. 寝ていると10秒待ってから正常に戻ります。または2以外の信号で死亡、スクリプトは返されたときにキャッシュされた信号2を無視し、カスタム_trap_N関数を実行します。
  2. しかし寝るとシグナル2キルすると、スクリプトは戻り時に組み込みSIGINTハンドラを実行し、user-define_trap_Nを実行せずに直接終了します。

関連情報