web-dev-qa-db-ja.com

3日ごとにbashスクリプトを文字通り実行する

3日ごとにシェルスクリプトを文字通り実行したい。 01 00 */3 * *でcrontabを使用しても、実際には条件を満たしません。31日目に実行され、その後月の1日目に再び実行されるためです。 */3構文は、1,4,7 ... 25,28,31と同じです。

スクリプト自体が条件をチェックし、3日が経過していない場合は終了する方法が必要です。そのため、crontabは毎日スクリプトを実行しますが、スクリプト自体は3日が経過したかどうかを確認します。

いくつかのコードも見つけましたが、構文エラーが発生しました。どんな助けでも感謝します。

if (! (date("z") % 3)) {
     exit;
}

main.sh: line 1: syntax error near unexpected token `"z"'
main.sh: line 1: `if (! (date("z") % 3)) {'
8
Taavi

最後の実行が少なくとも特定の時間前ではない場合、スクリプトを直ちに中止して終了するには、このメソッドを使用して、最後の実行日時を保存する外部ファイルを必要とします。

Bashスクリプトの先頭に次の行を追加します。

#!/bin/bash

# File that stores the last execution date in plain text:
datefile=/path/to/your/datefile

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Test if datefile exists and compare the difference between the stored date 
# and now with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test -f "$datefile" ; then
    if test "$(($(date "+%s")-$(date -f "$datefile" "+%s")))" -lt "$seconds" ; then
        echo "This script may not yet be started again."
        exit 1
    fi
fi

# Store the current date and time in datefile
date -R > "$datefile"

# Insert your normal script here:

意味のある値をdatefile=として設定し、seconds=の値をニーズに合わせて調整することを忘れないでください($((60*60*24*3))は3日間と評価されます)。


別のファイルが必要ない場合は、スクリプトの変更タイムスタンプに最後の実行時間を保存することもできます。ただし、スクリプトファイルに変更を加えると、3カウンターがリセットされ、スクリプトが正常に実行されているかのように扱われます。

それを実装するには、以下のスニペットをスクリプトファイルの先頭に追加します。

#!/bin/bash

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Compare the difference between this script's modification time stamp 
# and the current date with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test "$(($(date "+%s")-$(date -r "$0" "+%s")))" -lt "$seconds" ; then
    echo "This script may not yet be started again."
    exit 1
fi

# Store the current date as modification time stamp of this script file
touch -m -- "$0"

# Insert your normal script here:

繰り返しますが、seconds=の値をニーズに合わせて調整することを忘れないでください($((60*60*24*3))は3日間と評価されます)。

12
Byte Commander

Cronは本当にこのための間違ったツールです。 at と呼ばれる、一般的に使用され愛用されていないツールが実際にあります。 at'smainlyインタラクティブな使用のために設計されており、誰かがこれを行うためのより良い方法を見つけると確信しています。

私の場合、実行しているスクリプトをtestjobs.txtにリストし、読み取る行を含めます。

例として、私はこれをtestjobs.txtとして持っています

echo "cat" >> foo.txt
date >> foo.txt
at now + 3 days < testjobs.txt

私はあなたのシェルスクリプトかもしれない2つの罪のないコマンドを持っています。 echoを実行して、確定的な出力があることを確認し、必要に応じてコマンドが実行されることを確認します。 atがこのコマンドを実行すると、3日間atに新しいジョブを追加して終了します。 (私は1分でテストしました-これは動作します)

私は悪用された方法で呼ばれると確信していますが、コマンドの実行をスケジュールするための便利なツールat前のコマンドからの時間またはx日後。

12
Journeyman Geek

まず、上記のコードフラグメントは無効なBash構文であり、Perlのように見えます。次に、zdateパラメーターにより、数値のタイムゾーンが出力されます。 +%jは日数です。必要なもの:

if [[ ! $(( $(date +%j) % 3 )) ]] ;then
     exit
fi

しかし、あなたはまだ年末に奇妙さを見ているでしょう:

$ for i in 364 365  1 ; do echo "Day $i, $(( $i % 3 ))"; done
Day 364, 1
Day 365, 2
Day 1, 1

ファイルにカウントを保持し、それをテスト/更新することで、より良い運が得られるかもしれません。

3
waltinator

スクリプトを永続的に実行したままにできる場合は、次のようにします。

while true; do

[inert code here]

sleep 259200
done

このループは常に真であるため、常にコードを実行し、ループを再び開始する前に3日間待機します。

2
mkingsbu

Cronの代わりにanacronを使用できます。これは、必要なことを正確に行えるように設計されています。マンページから:

Anacronを使用すると、日単位で指定された頻度でコマンドを定期的に実行できます。 cron(8)とは異なり、マシンが継続的に実行されているとは想定していません。したがって、1日24時間稼働していないマシンで使用して、通常はcronによって制御される毎日、毎週、および毎月のジョブを制御できます。

実行されると、Anacronは設定ファイル(通常は/ etc/anacrontab(anacrontab(5)を参照))からジョブのリストを読み取ります。このファイルには、Anacronが制御するジョブのリストが含まれています。各ジョブエントリは、日単位の期間、分単位の遅延、一意のジョブ識別子、およびシェルコマンドを指定します。

Anacronは、各ジョブについて、このジョブが過去n日間に実行されたかどうかを確認します。nはそのジョブに指定された期間です。そうでない場合、Anacronは、遅延パラメーターとして指定された分数だけ待機した後、ジョブのシェルコマンドを実行します。

コマンドが終了すると、Anacronはそのジョブの特別なタイムスタンプファイルに日付を記録するため、いつ再実行するかを知ることができます。時間の計算には日付のみが使用されます。時間は使用されません。

2
Twinkles