月の最終日に実行するCRONジョブ


95

毎月最終日に実行されるCRONジョブを作成する必要があります。cPanelを使用して作成します。

どんな助けでもありがたいです。ありがとう

回答:


180

おそらく最も簡単な方法は、3つの別々のジョブを実行することです。

55 23 30 4,6,9,11        * myjob.sh
55 23 31 1,3,5,7,8,10,12 * myjob.sh
55 23 28 2               * myjob.sh

ただし、うるう年であっても2月28日に実行されるため、問題がある場合は別の方法を見つける必要があります。


ただし、通常は、毎月1日にできるだけ早くジョブを実行する方が、次のようにかなり簡単で適切です。

0 0 1 * * myjob.sh

そして処理するために、スクリプト修正前の月のデータを。

これにより、月の最後の日を特定する際の手間が省け、データを処理していると仮定して、その月のすべてのデータを確実に利用できます。その月の最終日の5分から真夜中に実行すると、そのときから真夜中に発生することが見逃される場合があります。

とにかく、これはほとんどの月末の仕事でそれを行うための通常の方法です。


それでも本当に月の最終日に、それを実行したい、一つの選択肢は、明日は(スクリプトの一部として、またはcrontabファイル自体のいずれかで)最初のであれば、単純に検出することです。

だから、次のようなもの:

55 23 28-31 * * [[ "$(date --date=tomorrow +\%d)" == "01" ]] && myjob.sh

あなたが比較的インテリジェントなdateプログラムを持っていると仮定すると、良いスタートになるはずです。

あなたのdateプログラムがあなたに相対的な日付を与えるほど十分に進んでいない場合は、次のような非常に単純なプログラムを作成して、明日の日を与えることができます(の機能は必要ありませんdate)。

#include <stdio.h>
#include <time.h>

int main (void) {
    // Get today, somewhere around midday (no DST issues).

    time_t noonish = time (0);
    struct tm *localtm = localtime (&noonish);
    localtm->tm_hour = 12;

    // Add one day (86,400 seconds).

    noonish = mktime (localtm) + 86400;
    localtm = localtime (&noonish);

    // Output just day of month.

    printf ("%d\n", localtm->tm_mday);

    return 0;
}

次に、次のコマンドを使用します(tomdom"明日の月"として呼び出した場合):

55 23 28-31 * * [[ "$(tomdom)" == "1" ]] && myjob.sh

あなたは、両方のため、エラーチェックを追加することを検討したい場合がありますがtime()mktime()返すことができる-1何かがうまくいかない場合。上記のコードは、簡単にするために、それを考慮に入れていません。


7
ええ、それは最終日ではなく、すべての最初の日に実行する方が簡単
かもしれません

1
確かに月の初日。PHPでのコードは次のようになります$ date = new DateTime( '2013-03-01'); $ date-> modify( '-1か月'); $ previousMonth = $ date-> format( 'Y-m'); // $ previousMonthは2013-02になりました。前月の商品を取得するクエリを作成します。
Lamy

うるう年2月29日のデータは失われます。これも考慮する必要があります。以下のサンダーラビットの回答はそれを考慮していますが、cronはうるう年の
Hari Swaminathan 14

1
@Hari、推奨されるソリューションは、月の最初に実行して、前月のデータを収集することです。その場合、2月29日は見逃せません。
paxdiablo 2014

1
うるう年を考慮:2回実行しても問題がない場合:55 23 28,29 2 * myjob.sh
radiantRazor

52

上記のものと同様に使用できる少し短い方法があります。あれは:

[ $(date -d +1day +%d) -eq 1 ] && echo "last day of month"

また、crontabエントリを更新して、28日から31日までしかチェックしないようにすることもできます。これは、月の他の日にそれを実行しても意味がないためです。それはあなたに与えるでしょう:

0 23 28-31 * * [ $(date -d +1day +%d) -eq 1 ] && myscript.sh

これをcrontabエントリとして機能させることができませんでした(何かをエスケープする必要があると思います)。ただし、crontabから呼び出されたシェルスクリプトでは問題なく動作しました。ちなみに、私が得たエラーはでした/bin/sh: -c: line 1: unexpected EOF while looking for matching ')'
Mark Rajcok、2014年

13
これはうまくいきます。crontabファイルでは、%をエスケープする必要があります。だから[ $(date -d +1day +\%d) -eq 1 ] && run_job
ColinM

確かに素敵なトリック!しかし、質問にはタグが付けられてposixおり、POSIX日付はサポートしていません"-d +1day":-\より複雑な(そして醜い)ソリューションは次のようになります:[ `date +\%d` -eq `cal | xargs echo | awk '{print $NF}'` ] && myscript.sh
ckujau

18

cronジョブをセットアップして、月の最初の日に実行します。次に、システムのクロックを1日進めるように変更します。


10
これは、システムクロックが常に間違っていることを意味します。申し訳ありませんが、これによりさらに問題が発生すると思います。次に-1。
Rudy

69
今、私はガリレオがどのように感じたかを知っています。
トムアンダーソン

7
@iconoclast:冗談というよりも公案のようなものだと思いたいです。
トムアンダーソン

14
これは本当に悪いアイデアだと思います。家でこれをしないでください、子供たち。
Pascal

11
@pascalbetzああ、人々は家でそれをすることができますが、彼らは実際に仕事でそれをするべきではありません。
トムアンダーソン

14

ウィキペディアの後、これはどうですか?

55 23 L * * /full/path/to/command

さて、それはどうですか?それ:「crontabファイルの悪い月のエラー、インストールできません。同じ編集を再試行しますか?」
webjunkie

12
明確にするために、ウィキペディアのエントリでは、「L」は非標準であることも言及されています。
sdupton 2013

10

paxdiabloのソリューションを適用して、2月28日 29日に実行します。29日のデータが28日を上書きします。

# min  hr  date     month          dow
  55   23  31     1,3,5,7,8,10,12   * /path/monthly_copy_data.sh
  55   23  30     4,6,9,11          * /path/monthly_copy_data.sh
  55   23  28,29  2                 * /path/monthly_copy_data.sh

4
もちろん、ジョブに処理中のすべてのデータを消去するなどの破壊的な側面がない限り:-)
paxdiablo

これは実際には痛みのないオプションです(技術が最も少ない)。4年に3回、を省略しただけではcronjobが早すぎることに気にしないかもしれません,29
Matt

@マット:えーと、crontabエントリに「4年に1回は早すぎる」と書いてあると55   23   28    2思いませんか?
G-Manは 'Reinstate Monica'を

@ G-Manはい、そうです、それに加えて、あなたはそれを29日に2回実行しました。
Matt

8

cronジョブを設定して、毎月実行し、次のようなシェルスクリプトを実行させることができます。このスクリプトは、明日の日数が今日の日数よりも少ないかどうか(つまり、明日が新しい月であるかどうか)を計算し、必要な処理を行います。

TODAY=`date +%d`
TOMORROW=`date +%d -d "1 day"`

# See if tomorrow's day is less than today's
if [ $TOMORROW -lt $TODAY ]; then
echo "This is the last day of the month"
# Do stuff...
fi

今日より少ないかどうかを確認することで何が得られるかはわかりません。1日かどうかを確認できるはずです。月の最初の日が2日または3
除き

7

@Indieソリューションに基づくcrontabでのより安全な方法(date+ への絶対パスを使用$()しても、すべてのcrontabシステムで機能するわけではありません):

0 23 28-31 * * [ `/bin/date -d +1day +\%d` -eq 1 ] && myscript.sh


5
#########################################################
# Memory Aid 
# environment    HOME=$HOME SHELL=$SHELL LOGNAME=$LOGNAME PATH=$PATH
#########################################################
#
# string         meaning
# ------         -------
# @reboot        Run once, at startup.
# @yearly        Run once a year, "0 0 1 1 *".
# @annually      (same as @yearly)
# @monthly       Run once a month, "0 0 1 * *".
# @weekly        Run once a week, "0 0 * * 0".
# @daily         Run once a day, "0 0 * * *".
# @midnight      (same as @daily)
# @hourly        Run once an hour, "0 * * * *".
#mm     hh      Mday    Mon     Dow     CMD # minute, hour, month-day month DayofW CMD
#........................................Minute of the hour
#|      .................................Hour in the day (0..23)
#|      |       .........................Day of month, 1..31 (mon,tue,wed)
#|      |       |       .................Month (1.12) Jan, Feb.. Dec
#|      |       |       |        ........day of the week 0-6  7==0
#|      |       |       |        |      |command to be executed
#V      V       V       V        V      V
*       *       28-31   *       *       [ `date -d +'1 day' +\%d` -eq 1 ] && echo "Tomorrow is the first today now is  `date`" >> ~/message
1       0       1       *       *       rm -f ~/message
*       *       28-31   *       *       [ `date -d +'1 day' +\%d` -eq 1 ] && echo "HOME=$HOME LOGNAME=$LOGNAME SHELL = $SHELL PATH=$PATH" 

5

AWS Cloudwatch cron実装(ラムダのスケジューリングなど)の場合、これは機能します。

55 23 L * ? *

毎月最終日の午後11時55分に実行されます。



3

すべての回答を1つのcron行に接続して、 dateコマンドます。

今日と明日の日付の違いを確認してください:

0 23 * * * root [ $(expr $(date +\%d -d '1 days') - $(date +\%d)  ) -le 0 ]  && echo true

これらの差が0未満の場合は、月を変更し、月の最後の日があることを意味します。


3
55 23 28-31 * * echo "[ $(date -d +1day +%d) -eq 1 ] && my.sh" | /bin/bash 

1
コマンドをエコーし​​、それをbashにパイプすることは、cronで作業する場合の最良の方法です。cronはbashではなくshを使用しているためです。bashが「which bash」を使用している場所を確認してください。FreeBSDでは/ usr / local / bin / bash、Linuxでは/ bin / bashです。
ドナルドダック

2

これはどうですか?

ユーザーの.bashprofile追加を編集:

export LAST_DAY_OF_MONTH=$(cal | awk '!/^$/{ print $NF }' | tail -1)

次に、このエントリをcrontabに追加します。

mm hh * * 1-7 [[ $(date +'%d') -eq $LAST_DAY_OF_MONTH ]] && /absolutepath/myscript.sh

0

月の最終日は、2月、3月など、月によって28〜31になります。ただし、どちらの場合でも、翌日は常に翌月の1日です。そのため、以下のコードを使用して、毎月の最終日に必ずジョブを実行するためにそれを使用できます。

0 8 28-31 * * [ "$(date +%d -d tomorrow)" = "01" ] && /your/script.sh
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.