while
bash
私のスクリプトには、最初と5秒の間隔で異なる操作を実行するループがあります。前のループの完了を許可します。 5秒間隔は、関数によってdo_different
設定されたグローバル変数で表されますheartbeat
。もう1つの問題は、通常のwhile
ループが未知の時間内に完了することです(RANDOM
以下のスクリプトで簡略化されています)。使用はcron
オプションではなく、ランダムなプロセスタイミングでもありません。
成功せずにパイプとプロセスの置き換えを試してみました。スクリプト全体をリファクタリングできます。
#!/bin/bash
function heartbeat {
do_different=true
while sleep 5s
do
do_different=true
done
}
heartbeat &
while true
do
if $do_different
then
echo 'Something different'
do_different=false
i=0
else
# process of random duration; not important
r=$(( 1 + RANDOM % 3 ))
sleep "${r}s"
i=$((i + r))
echo "$i"
fi
done
ベストアンサー1
まず、明確でない場合、問題のスクリプトはheartbeat
子プロセスで実行されるため、親シェルメモリのシェル変数を変更できないため、失敗します。
OPが望む精神に近いアプローチは次のとおりです。
#!/bin/bash
trap 'do_different=true' USR1
heartbeat() {
while sleep 5
do # If the parent process has gone away, the child should terminate.
kill -USR1 "$$" || exit
done
}
heartbeat &
heartbeat_pid=$!
trap 'kill "$heartbeat_pid"' 0
do_different=true
while true
do
if "$do_different"
then
echo 'Something different'
do_different=false
i=0
else
# process of random duration; not important
r=$(( 1 + RANDOM % 3 ))
sleep "$r"
i=$((i + r))
echo "$i"
fi
done
変更されたプロセスは、heartbeat
SIGUSR1シグナルを基本(親)シェルプロセスに送信します。このシグナルとSIGUSR2はユーザー/アプリケーションの使用のために予約されており、システムによって生成されてはなりません。このtrap
コマンドを使用すると、シェルスクリプトがシグナルをキャプチャできます。このtrap 'do_different=true' USR1
コマンドはSIGUSR1信号(5秒ごとに到着)をキャプチャし、do_different
信号が発生したときにフラグを設定するようにシェルに指示します。
heartbeat_pid
明らかに、子プロセスのプロセスID(PID)ですheartbeat
。このコマンドは、trap 'kill "$heartbeat_pid"' 0
スクリプトが終了したことを示す偽信号0が「受信」されたときに何が起こるかを定義します。 Shellがドアに「去った後、家に帰る途中で食料品を取ることを忘れないでください」と書かれたステッカーメモを貼るのと同じだと思います。exit
これは、スクリプトが最後に到達したり、ステートメントを実行したり(このスクリプトでは無限ループであるため、両方は発生しません)、割り込み信号(SIGINT、+によって生成されます)によって終了した場合CtrlCheartbeat