
スクリプトから5分の信号をキャプチャできますか?このような想像をしてみてください。
function dosomething {
echo "It's been 5 minutes."
}
trap dosomething SIGNAL-EVERY-5-MINUTES
while true
do
sleep 10
done
この例は意味がありません。 x回ごとに何かをキャプチャすることが可能かどうか尋ねてください。
編集する:sleep
@vinc17の答えに基づいて、メインシェルのコマンドがシグナルによって中断されないことがわかりましたUSR1
。これが私が望むものです。
#!/bin/bash
time=10
(
set -e
while true
do
sleep 30
# Since this is run as a subshell (instead of an external command),
# the parent pid is $$, not $PPID.
kill -USR1 $$
done
) &
finish() {
kill $!
echo "Closing."
exit 0
}
changetime() {
echo "Signal USR1 received."
time=$(( $RANDOM % 8 + 1))
}
trap changetime USR1
trap finish SIGINT
while true
do
echo "before sleep"
sleep $time
echo "after sleep"
done
出力、
before sleep
Signal USR1 received.
after sleep
before sleep
Signal USR1 received.
after sleep
before sleep
Signal USR1 received.
Closing.
編集2:同じ出力を得るために上記の例を編集しましたが、困難が追加されました。USR1
トラップ機能が睡眠時間を変更します。 30秒ごとに1から8の間でランダムな時間を選択してください。したがって、sleep
シグナルが時間を変更した場合は、基本スクリプトを終了する必要があります。私はこれが言葉にならないと主張しますが、これが可能かどうかを知る必要があります。
答え1
SIGALRM
たとえば、x回ごとにシェルスクリプトにシグナルを送信し、そのシグナルをトラップするプロセスを実行できます。このプロセスは、以下を実行するスクリプトです。
set -e
while true
do
sleep 300
kill -ALRM $PPID
done
デフォルトのシェルスクリプトによって起動された場合。
デフォルトのシェルスクリプトは、不要になったときにプロセスを終了し、/またはpidがもう存在しない場合(ただし競合状態があるとき)にプロセスを終了する必要があります。
(修正済み)注:デフォルトのシェルスクリプトはこのコマンドを使用し、それが組み込まれていると信号と誤って対話する可能性がsleep
あります。ALRM
sleep
sleep(3)
使用alarm(2)
。これsleep
シェルユーティリティのPOSIXの説明また、その理由について次のように述べました。SIGALRM 信号によって省電力モードが中断されると、終了状態は 0 になります。このユーティリティのほとんどの実装は、要求された完了時間に正常に到達したことを知らせるために、この信号の到着に依存するためです。したがって、これらの実装では、この場合と成功した完了のケースを区別することはできません。他の実装では、要求された時間が経過するまで信号をキャプチャし、スリープモードに戻るか、通常の信号終了手順を提供できます。「特定の実装で発生する可能性のある問題を回避するSIGUSR1
には。SIGUSR2
SIGALRM
以下は、サブシェルを使用する例です。動作を見やすくするために、5分期間(sleep 300
)を5秒期間(sleep 5
)に置き換えました。
#!/bin/sh
{
set -e
while true
do
sleep 5
# Since this is run as a subshell (instead of an external command),
# the parent pid is $$, not $PPID.
kill -USR1 $$
done
} &
trap 'echo "Signal USR1 received."' USR1
while true
do
date
sleep 1
done
Ctrl-Cを使用してスクリプトを中断できます。これが発生すると、サブシェルは終了しませんが、pidが再利用されないとコマンドがkill
失敗したため(kill: No such process
)一定時間(ここでは5秒)後にサブシェルが自動的に終了します。
答え2
はい。最も簡単な方法は、元の質問に記載されている方法で行うことです。これはほんの一部です。何次の5分以内にプロセスにシグナルを送信するには、別のサブプロセスを作成する必要があります。 @vinc17さんの書籍のページを取得し、間隔も5秒に短縮しました。
trap 'ME=$$
: $( (sleep 5
ps -p $ME >/dev/null 2>&1 && {
echo hey >/dev/tty
kill -USR1 $ME
})&)
' USR1; kill -USR1 $$
これにより、ゾンビ化を要求する長期実行プロセスが不要になります。代わりに、間隔ごとに親PIDへの新しい参照を取得する新しい単一目的カウンタがあります。また、親が去った後に死亡した場合、子供が自分で仕事をしようとしないように小さな検査も追加しました。
これを実行すると、5秒ごとに次のようになります。
hey
hey
hey
hey
hey
hey
hey
hey
hey
hey
この例では、同時に端末を一時停止することもできます。それ以外の場合は、プロセス全体をバックグラウンドに配置しようとしても何もしません。これは保存によるものです/dev/tty
。プロセス全体をバックグラウンドで実行する場合はファイルを選択し、そうでない場合は直接stty
ttyを呼び出し、必要に応じて再実行します。
答え3
USR1トラップが期待どおりに実行されるようにsleep $time
交換してください。sleep $time & wait $!
バラより他の質問に答えるまたは説明については、bashのマニュアルページのSIGNALSの章を参照してください。
私のシステムでは、ALRM信号がUSR1と同じように機能しているようです。