毎月の最終日をスケジュールします


10

月の最終日にスクリプトをスケジュールするように指示から読みました。

注:
毎月をカバーするようにdayofmonthの値を設定できないため、鋭い読者は、毎月の最終日にコマンドを実行するように設定する方法について疑問に思うかもしれません。この問題はLinuxおよびUnixのプログラマーを悩ませ、かなりの数の異なるソリューションを生み出しました。一般的な方法は、dateコマンドを使用して明日の日付が01かどうかを確認するif-thenステートメントを追加することです。

00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1

これにより、毎日正午にチェックされ、月の最終日であるかどうかが確認されます。最終日である場合は、cronがコマンドを実行します。

ここに画像の説明を入力してください

どのように機能し[`date +%d -d tomorrow` = 01 ]ますか?
述べるのは正しいthen; command1ですか?


それが逐語的であると確信していますか?ここに書かれているように、実際には機能しません
Michael Homer

スナップショットを投稿しました。@ MichaelHomer
Calculus

ありがとう!私はそれを一致させるためにフォーマットをいじりました-それはまだ完全には正しくありませんが、それは写真が言うことです。
Michael Homer

1
行方不明; endif
danblack 2018年

動作しません。構文エラーが含まれています:後にスペースが[なくfi、最後にスペースがありません。また、%crontabs では特別です。
クサラナンダ

回答:


17

概要

正しいコードは次のとおりです。

#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"

このスクリプトend_of_month.shを呼び出すと、cronでの呼び出しは次のようになります。

00 12 28-31 * * /path/to/script/end_of_month.sh command

これend_of_monthにより、28日目、29日目、30日目、および31日目にのみスクリプトが実行されます(内部的にはその日が月の最終日であることを確認します)。月の終わりを他の日に確認する必要はありません。

古いポスト。

これは、リチャードブルムの著書「Linuxコマンドラインとシェルスクリプティングバイブル」、Christine Bresnahan pp 442、第3版、John Wiley&Sons©2015からの引用です。

はい、それはそれが言うことですが、それは間違っている/不完全です:

  • クロージングがありませんfi
  • 空間との間でニーズ[と以下`
  • の代わりに$(…)を使用することを強くお勧めします`…`
  • 次のような展開を引用符で囲むことが重要です。"$(…)"
  • 追加があります;後は、then

どうやって知るの?(まあ、経験によると☺)しかし、あなたはShellcheckを試すことができます。本のコードを(アスタリスクの後に)貼り付けると、上記のエラーと「シバンがありません」が表示されます。Shellcheckでエラーのないスクリプトは次のとおりです。

#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi

書かれているのは「シェルコード」だからです。これは多くのシェルで機能する構文です。

shellcheckが触れていないいくつかの問題は次のとおりです。

  • これは、dateコマンドがGNU日付バージョンであることを前提としています。1 -d受け入れオプションtomorrow(busyboxのは、-dオプションを持っていますが、明日を理解していないとBSDが持つ値として-dオプションをが、時間の「表示」とは関係ありません)。

  • すべてのオプションのにフォーマットを設定することをお勧めしますdate -d tomorrow +'%d'

  • cronの開始時刻は常に現地時間です。これにより、DST(夏時間)が設定または設定解除された場合、1つのジョブが正確な日数より1時間早く開始されることがあります。

完了したのは、cronで呼び出すことができるシェルスクリプトです。次のように、スクリプトをさらに変更して、実行するプログラムまたはコマンドの引数を受け入れることができます(最終的に、正しいコード)。

#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"

このスクリプトend_of_month.shを呼び出すと、cronでの呼び出しは次のようになります。

00 12 28-31 * * /path/to/script/end_of_month.sh command

これend_of_monthにより、28日目、29日目、30日目、および31日目にのみスクリプトが実行されます(内部的にはその日が月の最終日であることを確認します)。月の終わりを他の日に確認する必要はありません。

正しいパスが含まれていることを確認してください。cron内のPATHは、ユーザーPATHと同じではありません(そうではありません)。

他の多くのユーティリティまたはスクリプトを呼び出す可能性のある、(以下に示すように)テストされた月末のスクリプトが1つあることに注意してください。

これにより、cronが完全なコマンドラインで生成する追加の問題も回避されます。

  • Cron %は、'またはで引用されている場合でも、コマンドラインを分割します"\ここでは機能します)。これは、cronジョブが失敗する一般的な方法です。

end_of_month.shfaketimeを使用してテストすることで、スクリプトが特定の日付で正しく機能するかどうかを確認できます(月末までに機能しないことを発見せずに)。

$ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
Command will be executed....

ast-open date(またはdateksh93がast-openの一部として構築された場合はksh93 の組み込み)は、date -d tomorrow +%sまたはdate +%s tomorrow)をサポートします。
ステファンChazelas

2
経験から(何度も)、スクリプトがfaketimeで正しく実行されていることをテストする方が、スケジュールされたジョブが機能しないことを確認するために月末まで待つよりもはるかに優れていることが証明されています。* * * * * echo "$(date -u +'date %c')" >>~/testfile引用符を忘れたために機能しないことを発見するのと同じです\%(毎月1回しか試行できないとデバッグが困難になります)。@Kusalananda
Isaac

8

構文エラーが修正され、コマンドが少し冗長になるように再編成されたと仮定します。

00 12 28-31 * * [ "$( date -d tomorrow +\%d )" != "01" ] || command1

これが実行されdate +%d -d tomorrowdate使用されているのはGNUであると想定)、明日の日付が2桁の数値として取得されます。番号がない場合には01、その後、今日は月の最後の日ではありません。その場合、試験は成功とcommand1されていない実行します。ジョブは、月の最終日になる可能性がある日の正午に実行されます。

元のコマンド:

00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1

これにはいくつかの問題があります:

  • の後にスペースはありません[
  • ;直後then
  • %はcronジョブ仕様で特別であり、エスケープする必要があります\%(を参照man 5 crontab)。
  • fi最後にと一致するfinalはありませんif

2
[ ... ] && command1代わりにを使用する場合の問題if...は、月の最終日ではない日に、cronジョブがゼロ以外の終了ステータスで終了し、その失敗を報告する必要がある場合があることです。を使用し[ "$(...)" != 01 ] || command1て問題を回避する別の方法です。
ステファンChazelas

1
元のコードのもう一つの問題はある;thencommand1
ステファンChazelas

@StéphaneChazelasワンライナーが嫌いなもう1つの理由は、読みにくいことです。
Kusalananda

DSTの変更によりcronの開始時刻がシフトするため、コマンドの連続実行間の時間差は(24時間)日の整数ではない場合があります。
Isaac

3
@cat引用するか"'(を除く\)のどちらを使用するかは関係ありません。パーセント記号%は、cronに2つの部分で改行させます。これは、cronを失敗させる通常の方法の1つです。
Isaac、

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.