Bashで終了していないプロセスのタイムアウト

Bashで終了していないプロセスのタイムアウト

メインスクリプトが実行中でタイムアウト内に完了しない場合は、完了したかどうかに応じてメインスクリプトで「何かを実行する」2番目の「遅いプロセス」を開始したいと思います。注:「遅いプロセス」がタイムアウトの前に完了した場合は、フルタイムアウトを待ちたくありません。

「遅いプロセス」が続き、パフォーマンスに関する統計とフォレンジックを収集できることを願っています。

使用を調べた停止するしかし、完了すると、私のスクリプトは終了します。

次の簡単な例を考えてみましょう。

メインディレクトリ

result=`timeout 3 ./slowprocess.sh`
if [ "$result" = "Complete" ]
then
 echo "Cool it completed, do stuff..."
else
 echo "It didn't complete, do something else..."
fi

遅いプロセス.sh

#!/bin/bash
start=`date +%s`
sleep 5
end=`date +%s`
total=`expr $end - $start`
echo $total >> /tmp/performance.log
echo "Complete"

ここではタイムアウトを使用してスクリプトが終了するため、何も起こりません/tmp/performance.log。終わりたいのですが、3秒で終わらなくても次のステップに進みたいslowprocess.shです。main.sh

答え1

ksh/bash/zshを使う:

{
  (./slowprocess.sh >&3 3>&-; echo "$?") |
    if read -t 3 status; then
      echo "Cool it completed with status $status, do stuff..."
    else
      echo "It didn't complete, do something else..."
    fi
} 3>&1

()のために復元できるように、元のstdoutをfd 3()にコピーし、残りのサブシェルの3>&1stdoutはパイプに移動します。slowprocess.sh>&3(...)read -t 3

または使用したい場合timeout(ここでGNUを想定timeout):

timeout --foreground 3 sh -c './slowprocess.sh;exit'

終了するのを防ぎます(これはslowprocess.shシェルプロセスで最後のコマンドを実行し、最適化された実装に;exit必要です)。sh

答え2

これはユビキタスシェルツールのみを使用するソリューションです。

sleepこれは、遅いプロセスをフォークし、バックグラウンドでwaitシェル組み込み待機に加えて、最初のプロセスが完了するのを待つと簡単に実行できます。みんな最初の作業だけでなく作業も実行する必要があります。

したがって、sleep遅いプロセスとバックグラウンドでaを分岐し、両方ともパイプを介して状態を報告し、パイプから出る最初の状態を読み取るようにします。

fifo=$(mktemp -u)  # if not on Linux, adapt to what your OS provides
mkfifo -m 600 "$fifo"
{ ./slowprocess.sh; echo z >"$fifo"; } &
sh -c 'sleep 3; echo a' >"$fifo" &
sleep_pgid=$!
read status <$fifo
case $status in
  a) echo "That process is taking a long time"; read ignored <$fifo;;
  z) echo "Done already"; kill -INT -$sleep_pgid;;
esac
rm "$fifo"

答え3

ブロックが発生してもslowprocess.shバックグラウンドで実行できるため、タイムアウト後も実行が続行される可能性があります。

のマニュアルページを参照して、後signalから使用することもできます。timeoutmain.shtimeout

timeoutガイドページから抜粋

`-s SIGNAL'
`--signal=SIGNAL'
     Send this SIGNAL to COMMAND on timeout, rather than the default
     `TERM' signal. SIGNAL may be a name like `HUP' or a number. Also
     see *Note Signal specifications::.

この信号を内部でキャッチする必要がありますmain.sh

timeoutさまざまな種類の障害に対してもさまざまな状態が返されます。以下を活用することもできます。

   Exit status:

     124 if COMMAND times out
     125 if `timeout' itself fails
     126 if COMMAND is found but cannot be invoked
     127 if COMMAND cannot be found
     the exit status of COMMAND otherwise

$?行が実行された後、変数に表示されますtimeout ...

答え4

以下は不要なジョブ制御出力を生成しますが、非常に単純な別の方法です。バックグラウンドプロセス "sleep nnn"を起動し、 "wait -n"を使用して最初のスリーププロセスと監視中のプロセスを待ちます。以下は、この技術のやや不器用な例です(即時通知に「set -o通知」を使用)。

$ (for I in $(seq 10); do sleep 1; echo $I ; done) & \
more> J1=$! ; \
more> sleep 5 & \
more> J2=$! ; \
more> time wait -n $J1 $J2
[1] 288160
[2] 288161
1
2
3
4
[2]+  Done                    sleep 5

real    0m5.006s
user    0m0.002s
sys 0m0.004s
$ 5
6
7
8
9
10
[1]+  Done                    ( for I in $(seq 10);
do
sleep 1; echo $I;
done )
$

$ (for I in $(seq 3); do sleep 1; echo $I ; done) & \
more> J1=$! ; \
more> sleep 5 & \
more> J2=$! ; \
more> time wait -n $J1 $J2
[1] 288256
[2] 288257
1
2
3
[1]-  Done                    ( for I in $(seq 3);
do
sleep 1; echo $I;
done )

real    0m3.025s
user    0m0.004s
sys 0m0.015s
$ [2]+  Done                    sleep 5
$

関連情報