次のようなBashスクリプトがあります。
#!/bin/bash
echo "Doing some initial work....";
/bin/start/main/server --nodaemon
スクリプトを実行しているbashシェルがSIGTERMシグナルを受信した場合、実行中のサーバーにSIGTERMも送信する必要があります(ブロックするため、トラップはできません)。それは可能ですか?
試してください:
#!/bin/bash
_term() {
echo "Caught SIGTERM signal!"
kill -TERM "$child" 2>/dev/null
}
trap _term SIGTERM
echo "Doing some initial work...";
/bin/start/main/server --nodaemon &
child=$!
wait "$child"
通常、bash
は、子プロセスの実行中はシグナルを無視します。 &
でサーバーを起動すると、シェルのジョブ制御システムのバックグラウンドになり、$!
はサーバーのPIDを保持します(wait
およびkill
で使用されます)。 wait
を呼び出すと、指定されたPID(サーバー)のジョブが終了するのを待ちますまたはシグナルが発生する。
シェルがSIGTERM
(またはサーバーが独立して終了)を受信すると、wait
呼び出しが返されます(サーバーの終了コード、またはシグナルが受信された場合はシグナル番号+ 128で終了)。 。その後、シェルがSIGTERMを受信した場合、シェルは終了する前にSIGTERMトラップハンドラとして指定された_term
関数を呼び出します(クリーンアップを実行し、kill
を使用して手動で信号をサーバープロセスに伝播します)。 。
BashはSIGTERMのようなシグナルを現在待機しているプロセスに転送しません。サーバーを推測してスクリプトを終了したい場合(サーバーを直接起動した場合と同様に、信号やその他を処理できるようにします)、 exec
を使用する必要があります。これにより、シェルが開かれているプロセスに置き換えられます:
#!/bin/bash
echo "Doing some initial work....";
exec /bin/start/main/server --nodaemon
何らかの理由でシェルを維持する必要がある場合(つまり、サーバーの終了後にクリーンアップを行う必要がある場合)、trap
、wait
、およびkill
。 SensorSmithの回答 を参照してください。
Andreas Veithenが指摘 (OPの例のように)呼び出しから戻る必要がない場合は、exec
コマンドを介して呼び出すだけで十分です( @ Stuart P 。ベントレーの答え )。そうでなければ、「伝統的な」trap 'kill $CHILDPID' TERM
(@cuonglmの答え)は開始ですが、wait
呼び出しは実際にはトラップハンドラの実行後に戻りますが、子プロセスが実際に終了する前でもかまいません。したがって、wait
への「余分な」呼び出しをお勧めします( @ user1463361の回答 )。
これは改善点ですが、まだシグナルがTERMシグナルの送信を再試行しない限り、プロセスが終了しない可能性があることを意味する競合状態がまだあります。脆弱性の窓は、トラップハンドラの登録と子のPIDの記録の間にあります。
以下はその脆弱性を排除します(再利用のために関数にパッケージ化されています)。
prep_term()
{
unset term_child_pid
unset term_kill_needed
trap 'handle_term' TERM INT
}
handle_term()
{
if [ "${term_child_pid}" ]; then
kill -TERM "${term_child_pid}" 2>/dev/null
else
term_kill_needed="yes"
fi
}
wait_term()
{
term_child_pid=$!
if [ "${term_kill_needed}" ]; then
kill -TERM "${term_child_pid}" 2>/dev/null
fi
wait ${term_child_pid}
trap - TERM INT
wait ${term_child_pid}
}
# EXAMPLE USAGE
prep_term
/bin/something &
wait_term
Waitコマンドが実際に終了する前にプロセスが強制終了されたため、提供されたソリューションが機能しません。私はその記事を見つけました http://veithen.github.io/2014/11/16/sigterm-propagation.html 、カスタムshを使用してOpenShiftでアプリケーションを開始した場合、最後のスニペットはうまく機能しますランナー。 Javaプロセスが1の場合、スレッドダンプを取得する機能が必要になるため、shスクリプトが必要です。
trap 'kill -TERM $PID' TERM INT
$Java_EXECUTABLE $Java_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?