web-dev-qa-db-ja.com

特定の時間の次の発生まで眠る

「4:00」のような特定の時間が次に発生するまでスリープする一連のコマンドまたは単一のコマンドが必要です。

どうすればいいですか?

atコマンドまたはcronjobは、現在使用しているスクリプトを残してはいけないため、オプションではありません。

私が話している特定のケースは、画面で実行されるスクリプトです。スクリプトのある時点で必要な多くの重要な変数が格納されているため、スクリプト自体によるスクリプトの実行を停止しないことが非常に重要です。スクリプトは、常に通常の方法で実行されるとは限りません。特定の時間に実行する必要があるだけです。

スクリプトがファイルや、cronjobsや他の画面などの他のタスクを作成する必要がある場合は、非常に有益です。これは単にデザインの問題です。

私はちょうどいい考えを持っていました:

difference=$(($(date -d "4:00" +%s) - $(date +%s)))

if [ $difference -lt 0 ]
then
    sleep $((86400 + difference))
else
    sleep $difference
fi

もっと良いアイデアはありますか?

必要に応じて詳細が追加されます!

11
BrainStone

terdonの提案は機能しますが、私のほうが効率的です。

difference=$(($(date -d "4:00" +%s) - $(date +%s)))

if [ $difference -lt 0 ]
then
    sleep $((86400 + difference))
else
    sleep $difference
fi

これは、指定された時間と現在の時間の差を秒単位で計算しています。数が負の場合は、1日の秒数(正確には86400)を追加して、スリープする秒数を取得する必要があります。数が正数の場合は、そのまま使用できます。

17
BrainStone

それがシェルスクリプトであると仮定すると、これはうまくいくはずです:

while [ $(date +%H:%M) != "04:00" ]; do sleep 1; done

それは24時間です。これを4:00 AMと4:00 PMの両方で続行する場合は、代わりにこれを使用します。

while [ $(date +%I:%M) != "04:00" ]; do sleep 1; done
10
terdon

OpenBSDでは、次のコマンドを使用して_*/5_ 5分 crontab(5)を圧縮できます。 1時間ごとに_00_ジョブを実行します(正確な間隔で同じタスクを実行しながら、生成される電子メールの数を減らすため):

_#!/bin/sh -x
for k in $(jot 12 00 55)
  do
  echo $(date) doing stuff
  sleep $(expr $(date -j +%s $(printf %02d $(expr $k + 5))) - $(date -j +%s))
done
_

date(1) も、最後の反復で sleep(1) を意図的に壊すことに注意してください。 _60_分は有効な時間ではないので(有効でない限り)、メールレポートを取得する前に余分な時間を待つ必要はありません。

また、繰り返しの1つに割り当てられた時間が5分を超える場合、sleepも同様に、まったくスリープ状態にならないことにより、意図的に失敗します(コマンドラインオプションとして解釈される負の数が原因です)。 、次の1時間または永遠に循環するのではなく)、ジョブが割り当てられた時間内にまだ完了できることを確認します(たとえば、反復の1つだけが5分以上かかる場合でも、次の1時間に何も回り込むことなく、追いつく時間です。

printf(1) が必要なのは、dateが分の指定に正確に2桁を期待しているためです。

0
cnst