回答:
試してください:
#!/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を受信した場合、_term
終了する前にSIGTERMトラップハンドラとして指定された関数を呼び出します(クリーンアップを実行し、を使用して信号をサーバープロセスに手動で伝達しますkill
)。
exec /bin/start/main/server --nodaemon
(この場合、シェルプロセスはサーバープロセスに置き換えられ、シグナルを伝播する必要はありません)か、を使用しますが/bin/start/main/server --nodaemon &
、exec
実際には意味がありません。
_term()
する場合は、関数内でwait "$child"
再度実行する必要があります。これは、シェルスクリプトが終了するのを待ってから再起動する他の監視プロセスがある場合、またはEXIT
何らかのクリーンアップを行うためにトラップして、子プロセスが終了した後にのみ実行するようにニードする場合に必要になることがあります。
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. Bentleyの答え)。それ以外の場合、「従来の」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
待機コマンドが実際に終了する前にプロセスが強制終了されたため、提供されたソリューションが機能しません。その記事http://veithen.github.io/2014/11/16/sigterm-propagation.htmlを見つけました。アプリケーションの私の場合、最後のスニペットは、カスタムshランナーを使用してOpenShiftで起動しました。shプロセスが必要なのは、JavaプロセスのPIDが1の場合には不可能なスレッドダンプを取得する必要があるためです。
trap 'kill -TERM $PID' TERM INT
$JAVA_EXECUTABLE $JAVA_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?