CRON işi ayın son günü çalıştırılacak


97

Her ayın son günü çalışacak bir CRON işi oluşturmam gerekiyor. CPanel kullanarak oluşturacağım.

Herhangi bir yardım takdir edilmektedir. Teşekkürler

Yanıtlar:


187

Muhtemelen en kolay yol, üç ayrı işi yapmaktır:

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

Bu, 28 Şubat'ta devam edecek, artık yıllarda bile, bu bir sorunsa, başka bir yol bulmanız gerekecek.


Bununla birlikte, işi her ayın ilk gününde mümkün olan en kısa sürede yürütmek genellikle hem çok daha kolay hem de doğrudur.

0 0 1 * * myjob.sh

ve önceki ayın verilerini işlemek için komut dosyasını değiştirin .

Bu, ayın son hangi gün olduğunu belirlerken karşılaşabileceğiniz sorunları ortadan kaldırır ve aynı zamanda verileri işlediğiniz varsayılarak o aya ait tüm verilerin kullanılabilir olmasını sağlar. Ayın son günü beş dakika ile gece yarısına kadar koşmak, o zamandan gece yarısı arasında olan herhangi bir şeyi kaçırdığınızı görebilir.

Bu, çoğu ay sonu işi için bunu yapmanın olağan yoludur.


Hala gerçekten ayın son günü çalıştırmak istiyorsanız, bir seçenek yarının ilk olup olmadığını belirlemektir (betiğinizin bir parçası olarak veya crontab'ın kendisinde).

Yani, şöyle bir şey:

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

görece akıllı bir dateprogramınız olduğunu varsayarak, iyi bir başlangıç ​​olmalıdır .

Senin Eğer dateprogram göreli tarihlere vermek oldukça gelişmiş yeterli değildir, sadece (eğer gerekmez size ayın yarının gün vermek için birlikte çok basit bir program koyabilirsiniz tam gücünü dategibi):

#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;
}

ve sonra kullanın ( tomdom"ayın yarının günü" olarak adlandırdığınızı varsayarak ):

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

Her ikisinden de hata kontrolü eklemeyi düşünebilirsiniz time()ve bir şeyler ters giderse mktime()geri dönebilirsiniz -1. Yukarıdaki kod, basitlik açısından, bunu hesaba katmaz.


7
evet son gün yerine her gün koşmak daha kolay olabilir :)
Utku Dalmaz

1
Gerçekten ayın 1. günü. PHP $ date = new DateTime ('2013-03-01') 'de kodun nasıl görüneceği aşağıda açıklanmıştır; $ tarih-> değiştir ('- 1 ay'); $ öncekiMonth = $ tarih-> biçim ('Y-a'); // $ previousMonth artık 2013-02. Önceki aya ait ürünleri getirmek için sorgu oluşturun.
Yasen

Artık yıl 29 Şubat verileri kaybolacak, bunu da dikkate almamız gerekiyor. Aşağıdaki Thunder Rabbit cevabı bunu düşünün, ancak cron artık yılın Şubat ayında iki kez koşuyor
Hari Swaminathan

1
@Hari, tercih edilen çözüm ayın ilk günü çalıştırmak ve önceki ayın verilerini toplamak olacaktır. Bu durumda 29 Şubat kaçırılmayacaktır.
paxdiablo

1
Artık yılları göz önünde bulundurarak: ve iki kez çalışmasının bir sakıncası yoksa: 55 23 28,29 2 * myjob.sh
radiantRazor

53

Yukarıdakilerden birine benzer şekilde kullanılabilecek biraz daha kısa bir yöntem var. Yani:

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

Ayrıca, crontab girişi, ayın diğer günlerinde onu çalıştırmanın anlamsız olması nedeniyle yalnızca 28 ila 31. günleri kontrol edecek şekilde güncellenebilir. Hangi size verecektir:

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

Bunun bir crontab girişi olarak çalışmasını sağlayamadım (sanırım bir şeyin kaçılması gerekiyor). Bununla birlikte, crontab'dan adı verilen bir kabuk betiğinde iyi çalıştı. Bilginize, aldığım hata oldu /bin/sh: -c: line 1: unexpected EOF while looking for matching ')'.
Mark Rajcok

13
Bu harika çalışıyor. Crontab dosyasında% kaçılmalıdır. So[ $(date -d +1day +\%d) -eq 1 ] && run_job
ColinM

Gerçekten güzel numara! Ancak soru etiketlendi posixve POSIX tarihi"-d +1day" şunları desteklemiyor : - \ Daha karmaşık (ve çirkin) bir çözüm şu olabilir:[ `date +\%d` -eq `cal | xargs echo | awk '{print $NF}'` ] && myscript.sh
ckujau

15

Ayın ilk gününde çalışacak bir cron işi ayarlayın. Ardından sistemin saatini bir gün ileri olacak şekilde değiştirin.


11
bu, sistem saatinin her zaman yanlış olacağı anlamına gelir. Üzgünüm ama bunun daha fazla soruna neden olacağını düşünüyorum. -1 o zaman.
Rudy

71
Artık Galileo'nun nasıl hissettiğini anlıyorum.
Tom Anderson

7
@iconoclast: Bunu bir şakadan çok bir koan olarak düşünmek istiyorum.
Tom Anderson

15
Bunun gerçekten kötü VE parlak bir fikir olduğunu düşünüyorum. Bunu evde yapmayın çocuklar.
Pascal

12
@pascalbetz Oh, insanlar bunu evde yapabilir, ama gerçekten işte yapmamalılar.
Tom Anderson

14

Wikipedia'dan sonra buna ne dersiniz?

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

Peki ya o? Bu: "crontab dosyasında ayın kötü günü hataları, yüklenemiyor. Aynı düzenlemeyi yeniden denemek ister misiniz?"
webjunkie

12
Daha açık olmak gerekirse, o wikipedia girişi aynı zamanda "L" nin standart olmadığından da bahsediyor.
sdupton

10

Paxdiablo'nun çözümünü uyarlayarak 28 ve 29 Şubat'ta koşuyorum . 29'undan gelen veriler, 28'inin üzerine yazılır.

# 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
İşin, işlenirken tüm verileri temizlemek gibi bazı yıkıcı yönleri olmadığı sürece :-)
paxdiablo

Bu aslında ağrısız bir seçenektir (en az teknik) ve ,29.
Matt

@Matt: Ümmü, bunu çok erken bir gün çalışacağı anlamına gelmez kez sizin crontab girdisi diyorsa dört yıl içinde 55   23   28    2?
G-Man

@ G-Man Evet, haklısınız ve bunun da ötesinde, 29'unda ikinci kez çalıştırıyorsunuz.
Mat

8

Ayın her günü çalışacak bir cron işi kurabilir ve aşağıdaki gibi bir kabuk betiğini çalıştırabilirsiniz. Bu komut dosyası, yarının gün sayısının bugünkünden daha az olup olmadığını hesaplar (yani yarın yeni bir ay ise) ve sonra istediğinizi yapar.

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

Bugünden daha az olup olmadığını kontrol ederek ne kazandığınızdan emin değilim - sadece 1'inci olup olmadığını kontrol edebilmelisiniz. Ayın ilk günü 2. veya 3.
olamazsa

7

@Indie çözümüne dayalı bir crontab'de daha güvenli bir yöntem için ( date+ ' $()ya mutlak yolu kullanın , tüm crontab sistemlerinde çalışmaz):

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 uygulaması için (Lambda'ları Planlama vb.) Şu şekilde çalışır:

55 23 L * ? *

Her ayın son günü 23: 55'te yayınlanıyor.


4
00 23 * * * [[ $(date +'%d') -eq $(cal | awk '!/^$/{ print $NF }' | tail -1) ]] && job

Bir göz atın ilgili soru unix.com forumunda.


3

Tüm cevapları tek bir cron satırına bağlayabilir ve yalnızca datekomutu kullanabilirsiniz .

Sadece bugün olan ve yarın olan ayın günü arasındaki farkı kontrol edin:

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

Bu fark 0'ın altında ise ayı değiştiririz ve ayın son günü vardır.


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

1
cron ile çalışmanın en iyi yolu komutu yankılamak ve onu bash'a aktarmaktır. Cron bash değil sh kullandığından beri. Bash'inizin 'hangi bash'ı kullandığını kontrol edin. FreeBSD'de Linux / bin / bash'da / usr / local / bin / bash şeklindedir.
Ördek Donald

2

Peki buna ne dersin?

kullanıcının .bashprofileeklemesini düzenle :

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

Ardından bu girişi crontab'e ekleyin:

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

1

Ayın son günü hangi ay olduğuna göre (Şubat, Mart vb.) 28-31 olabilir. Ancak her iki durumda da ertesi gün her zaman sonraki ayın 1'idir. Dolayısıyla, aşağıdaki kodu kullanarak her zaman bir ayın son gününde bazı işler yürüttüğümüzden emin olmak için bunu kullanabiliriz:

0 8 28-31 * * [ "$(date +%d -d tomorrow)" = "01" ] && /your/script.sh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.