Her ayın son gününü planla


10

Bir komut dosyasını ayın son gününde bir komut dosyası zamanlamak için okudum:

Not:
Zeki okuyucu, her ayın son gününde nasıl çalıştırılacağını nasıl ayarlayabileceğinizi merak ediyor olabilir çünkü dayofmonth değerini her ay kapsayacak şekilde ayarlayamazsınız. Bu sorun Linux ve Unix programcılarını rahatsız etti ve birkaç farklı çözüm üretti. Yaygın bir yöntem, yarının tarihinin 01 olup olmadığını kontrol etmek için date komutunu kullanan bir if-then ifadesi eklemektir:

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

Bu, her gün öğlen 12'de kontrol eder ve ayın son günü olup olmadığını kontrol eder ve eğer öyleyse cron komutu çalıştırır.

resim açıklamasını buraya girin

Nasıl [`date +%d -d tomorrow` = 01 ]çalışır?
Belirtmek doğru then; command1mu?


Bunun söylediklerini aynen olduğundan emin misin? Aslında burada yazıldığı gibi değil iş.
Michael Homer

Anlık görüntüyü gönderdim. @ MichaelHomer
Matematik

Teşekkürler! Eşleştirmek için biçimlendirme ile uğraştım - hala tam olarak doğru değil, ancak resmin söylediği şey bu.
Michael Homer

1
Kayıp ; endifmı?
danblack

Çalışmıyor. Sözdizimi hataları içerir: Sonrasında boşluk [yok five sonunda boşluk yok . Ayrıca, %crontabs özeldir.
Kusalananda

Yanıtlar:


17

Öz

Doğru kod şöyle olmalıdır:

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

Bu komut dosyasını end_of_month.shçağırın ve cron'daki çağrı basitçe:

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

Bu, senaryoyu end_of_month(dahili olarak günün ayın son günü olup olmadığını kontrol edecektir) sadece 28, 29, 30 ve 31. günlerde çalıştıracaktır. Diğer günlerde ay sonunu kontrol etmeye gerek yoktur.

Eski yazı.

Richard Blum, Christine Bresnahan s. 442, Üçüncü Baskı, John Wiley & Sons © 2015 tarafından yazılan "Linux Komut Satırı ve Shell Scripting İncil" kitabından bir alıntıdır.

Evet, söylediği bu, ancak bu yanlış / eksik:

  • Kapanış yok fi.
  • [Aşağıdakiler ile aşağıdakiler arasında boşluk gerekir `.
  • Bunun yerine $ (…) kullanılması önemle tavsiye edilir `…`.
  • Gibi genişletmelerde tırnak işaretleri kullanmanız önemlidir."$(…)"
  • ;Sonra bir ek varthen

Nasıl bilebilirim? (iyi, deneyime göre ☺) ama Shellcheck'i deneyebilirsiniz . Kodu kitaptan yapıştırın (yıldız işaretlerinden sonra) ve yukarıda listelenen hataları artı bir "eksik sapma" gösterecektir. Shellcheck'te hatasız bir komut dosyası şudur:

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

Yazılan şey "kabuk kodu" olduğu için bu site çalışır. Bu, birçok kabukta çalışan bir sözdizimidir.

Shellcheck'in bahsetmediği bazı konular:

  • Date komutunun GNU tarih sürümü olduğu varsayılmaktadır. Bir değer olarak -dkabul eden seçeneğe sahip olan tomorrow(meşgul kutusunun -d seçeneği vardır, ancak yarını anlamamaktadır ve BSD'nin bir -dseçeneği vardır, ancak zamanın "gösterimi" ile ilişkili değildir).

  • Tüm seçeneklerden sonra formatı ayarlamak daha iyidir date -d tomorrow +'%d'.

  • Cron başlangıç ​​zamanı her zaman yerel saattedir ve DST (gün ışığından yararlanma saati) ayarlanmış veya ayarlanmamışsa, bir işin tam gün sayımından 1 saat önce başlamasını sağlayabilir.

Yaptığımız şey cron ile çağrılabilecek bir kabuk betiğidir. Komut dosyasını, programın veya yürütülecek komutun argümanlarını kabul edecek şekilde, örneğin şu şekilde değiştirebiliriz (son olarak, doğru kod):

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

Bu komut dosyasını end_of_month.shçağırın ve cron'daki çağrı basitçe:

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

Bu, senaryoyu end_of_month(dahili olarak günün ayın son günü olup olmadığını kontrol edecektir) sadece 28, 29, 30 ve 31. günlerde çalıştıracaktır. Diğer günlerde ay sonunu kontrol etmeye gerek yoktur.

Doğru yolun dahil edildiğinden emin olun. Cron içindeki PATH, (PATH) kullanıcı PATH'si ile aynı olmayacaktır (büyük olasılıkla).

Not olduğunu bir ay script sonu test (aşağıda belirtildiği gibi) birçok araç veya komut dosyalarını diyebiliriz söyledi.

Bu, cron'un tam komut satırıyla oluşturduğu ek sorunu da önler:

  • Cron %, 'veya ile belirtilen bile olsa komut satırını böler "(yalnızca \burada çalışır). Bu, cron işlerinin başarısız olduğu yaygın bir yoldur.

Test edebilirsiniz end_of_month.shkomut faketime ile test ederek (bu işi yapmaz keşfetmeye ay sonuna kadar beklemeden) bazı tarihte düzgün çalışır:

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

ast-open date(veya dateksh93 ast-open'in bir parçası olarak inşa edilmişse ksh93'ün yerleşimi) destekliyor date -d tomorrow +%sveya date +%s tomorrow).
Stéphane Chazelas

2
Deneyimler (birçok kez) planlanan işin işe yaramadığını bulmak için ayın sonuna kadar beklemekten ziyade faketime ile doğru çalışan betiği test etmenin çok daha iyi olduğunu kanıtlamıştır. Bu * * * * * echo "$(date -u +'date %c')" >>~/testfileişe yaramaz keşfetmek gibi \%(biri her ay sadece bir deneyin mümkün ise hata ayıklamak zor olur) alıntı unuttum gibi . Kusalananda
Isaac

8

Sözdizimi hatalarının düzeltildiğini ve komutun daha az ayrıntılı olması için biraz yeniden düzenlendiğini varsayarsak:

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

Yarının tarihini iki basamaklı bir sayı olarak almak için (kullanılan date +%d -d tomorrowGNU dateolduğu varsayılarak) çalışır . Sayı değilse 01, bugün ayın son günü değildir. Bu durumda, testler başarılı ve command1edilir değil idam. İş, muhtemelen ayın son günü olabilecek günlerde öğlen devam eder.

Orijinal komut:

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

Bunun birkaç sorunu var:

  • Sonra boşluk yok [.
  • A ;hemen sonra then.
  • %cron iş şartnamelerinde özeldir ve \%(bkz man 5 crontab.)
  • fiSonunda ile eşleşen bir final yok if.

2
Bunun [ ... ] && command1yerine kullanımdaki sorun if..., ayın son günü olmayan günlerde, cron işinin sıfır olmayan bir çıkış durumu ile sona ereceği ve bu hatanın bildirilmesi gerekebileceğidir. Kullanmak [ "$(...)" != 01 ] || command1sorunu önlemenin başka bir yoludur.
Stéphane Chazelas

1
Orijinal kodla ilgili bir başka sorun da ; aralarında thenve command1.
Stéphane Chazelas

@ StéphaneChazelas Tek gömleklerden hoşlanmamın bir başka nedeni de, bunların okunması zordur.
Kusalananda

Bir DST değişikliği cronun başlangıç ​​zamanını değiştireceğinden, komutun art arda çalıştırılması arasındaki zaman farkı (24 saat) tam gün miktarı olmayabilir.
Isaac

3
@cat Yüzde işaretinin cronu iki parçaya ayırmasını nasıl sağlayacağınız ya "da '(hariç \) önemli değil %. Bu, cronun başarısız olmasının olağan bir yoludur.
Isaac

-1

Her ayın son günü planlamak için, deneyebilirsiniz: 0 0 15,L * *.

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.