あなたの例と受け入れられた答えの両方が非常に複雑です。なぜのみ timeout
を使用 まさにだから そのユースケース? timeout
コマンドには組み込みのオプションもあります (-k
) SIGKILL
を送信する コマンドを終了する最初のシグナルを送信した後 (SIGTERM
デフォルトでは) 最初のシグナルを送信した後もコマンドが実行中の場合 (man timeout
を参照) ).
スクリプトが必ずしも wait
を必要としない場合 待ってから制御フローを再開します。
timeout -k 60s 60s app1 &
timeout -k 60s 60s app2 &
# [...]
ただし、その場合は timeout
を保存するだけで簡単です 代わりに PID:
pids=()
timeout -k 60s 60s app1 &
pids+=($!)
timeout -k 60s 60s app2 &
pids+=($!)
wait "${pids[@]}"
# [...]
例
$ cat t.sh
#!/bin/bash
echo "$(date +%H:%M:%S): start"
pids=()
timeout 10 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 1 terminated successfully"' &
pids+=($!)
timeout 2 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 2 terminated successfully"' &
pids+=($!)
wait "${pids[@]}"
echo "$(date +%H:%M:%S): done waiting. both jobs terminated on their own or via timeout; resuming script"
.
$ ./t.sh
08:59:42: start
08:59:47: job 1 terminated successfully
08:59:47: done waiting. both jobs terminated on their own or via timeout; resuming script
PID をファイルに書き込み、次のようにアプリを起動します:
pidFile=...
( app ; rm $pidFile ; ) &
pid=$!
echo $pid > $pidFile
( sleep 60 ; if [[ -e $pidFile ]]; then killChildrenOf $pid ; fi ; ) &
killerPid=$!
wait $pid
kill $killerPid
これにより、タイムアウトのためにスリープし、それまでに完了していない場合はそのプロセスを強制終了する別のプロセスが作成されます。
プロセスがより速く完了すると、PID ファイルが削除され、キラー プロセスが終了します。
killChildrenOf
すべてのプロセスをフェッチし、特定の PID のすべての子プロセスを強制終了するスクリプトです。この機能を実装するさまざまな方法については、この質問の回答を参照してください:すべての子プロセスを強制終了する最良の方法
BASH の外に出たい場合は、PID とタイムアウトをディレクトリに書き込んで、そのディレクトリを監視できます。約 1 分ごとにエントリを読み、どのプロセスがまだ残っているか、タイムアウトになっているかどうかを確認してください。
編集 プロセスが正常に終了したかどうかを知りたい場合は、kill -0 $pid
を使用できます。
EDIT2 または、プロセス グループを試すこともできます。 kevinarpe は言った:PID(146322) の PGID を取得するには:
ps -fjww -p 146322 | tail -n 1 | awk '{ print $4 }'
私の場合:145974. その後、PGID を kill の特別なオプションと共に使用して、グループ内のすべてのプロセスを終了できます:kill -- -145974