Czytam z instrukcji, jak zaplanować skrypt na ostatni dzień miesiąca:
Uwaga:
bystry czytelnik może zastanawiać się, w jaki sposób można ustawić polecenie wykonywania w ostatnim dniu każdego miesiąca, ponieważ nie można ustawić wartości dayofmonth na pokrycie każdego miesiąca. Ten problem nękał programistów Linuksa i Uniksa i stworzył całkiem sporo różnych rozwiązań. Popularną metodą jest dodanie instrukcji if-then, która używa polecenia date, aby sprawdzić, czy jutrzejsza data to 01:00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
Sprawdza to codziennie o godzinie 12, aby sprawdzić, czy jest to ostatni dzień miesiąca, a jeśli tak, cron uruchamia polecenie.
Jak [`date +%d -d tomorrow` = 01 ]
działa
Czy poprawne jest stwierdzenie then; command1
?
shell-script
cron
date
test
Rachunek różniczkowy
źródło
źródło
; endif
?[
i brakfi
na końcu. Ponadto%
jest wyjątkowy w crontabs.Odpowiedzi:
Abstrakcyjny
Prawidłowy kod powinien być:
Wywołaj ten skrypt,
end_of_month.sh
a wywołanie w cron jest po prostu:Spowodowałoby to uruchomienie skryptu
end_of_month
(który wewnętrznie sprawdzi, czy dzień jest ostatnim dniem miesiąca) tylko w dniach 28, 29, 30 i 31. Nie ma potrzeby sprawdzania końca miesiąca w żadnym innym dniu.Stary post
To cytat z książki „Linux Command Line and Shell Scripting Bible” Richarda Bluma, Christine Bresnahan str. 442, wydanie trzecie, John Wiley & Sons © 2015.
Tak, tak jest napisane, ale to źle / niekompletnie:
fi
.[
i poniżej`
.`…`
."$(…)"
;
pothen
Skąd mam wiedzieć? (cóż, z doświadczenia ☺), ale możesz wypróbować Shellcheck . Wklej kod z książki (po gwiazdkach), a zobaczysz błędy wymienione powyżej oraz „brakujący shebang”. Skrypt bez błędów w Shellcheck jest następujący:
#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
Ta strona działa, ponieważ napisano „kod powłoki”. To jest składnia, która działa w wielu powłokach.
Niektóre problemy, o których Shellcheck nie wspomina, to:
Zakłada się, że polecenie daty jest wersją daty GNU. Ten z
-d
opcją, która przyjmujetomorrow
jako wartość (busybox ma opcję -d, ale nie rozumie jutra, a BSD ma-d
opcję, ale nie jest związana z „wyświetlaniem” czasu).Lepiej ustawić format po wszystkich opcjach
date -d tomorrow +'%d'
.Czas rozpoczęcia crona jest zawsze podany w czasie lokalnym, co może spowodować rozpoczęcie pracy o 1 godzinę wcześniej niż dokładna liczba dni, jeśli DST (czas letni) został ustawiony lub rozbrojony.
To, co zrobiliśmy, to skrypt powłoki, który można wywołać za pomocą crona. Możemy dalej modyfikować skrypt, aby akceptował argumenty programu lub polecenia do wykonania, w ten sposób (w końcu poprawny kod):
Wywołaj ten skrypt,
end_of_month.sh
a wywołanie w cron jest po prostu:Spowodowałoby to uruchomienie skryptu
end_of_month
(który wewnętrznie sprawdzi, czy dzień jest ostatnim dniem miesiąca) tylko w dniach 28, 29, 30 i 31. Nie ma potrzeby sprawdzania końca miesiąca w żadnym innym dniu.Upewnij się, że podana jest poprawna ścieżka. ŚCIEŻKA wewnątrz crona nie będzie (mało prawdopodobna) taka sama jak ŚCIEŻKA użytkownika.
Należy pamiętać, że istnieje jeden koniec miesiąca skryptu badanego (jak pokazano poniżej), które mogą wywołać wiele innych narzędzi i skryptów.
Pozwoli to również uniknąć dodatkowego problemu generowanego przez cron z pełnym wierszem poleceń:
%
nawet jeśli jest cytowana za pomocą'
lub"
(\
działa tylko tutaj). Jest to powszechny sposób na niepowodzenie zadań CRON.Możesz sprawdzić, czy
end_of_month.sh
skrypt działa poprawnie w określonym dniu (nie czekając do końca miesiąca, aby odkryć, że nie działa), testując go z faketime:źródło
date
(lubdate
wbudowany ksh93, jeśli ksh93 został zbudowany jako część ast-open) obsługujedate -d tomorrow +%s
lubdate +%s tomorrow
).* * * * * echo "$(date -u +'date %c')" >>~/testfile
nie zadziała, ponieważ zapomniałeś podać cytat\%
(co staje się trudne do debugowania, jeśli możliwa jest tylko jedna próba każdego miesiąca). @KusalanandaZakładając, że błędy składniowe zostały naprawione, a polecenie nieznacznie przeformułowało, aby było mniej szczegółowe:
Działa to
date +%d -d tomorrow
(zakładając,date
że używany jest GNU ), aby uzyskać jutrzejszą datę jako dwucyfrową liczbę. Jeśli liczba nie jest01
, to dzisiaj nie jest ostatni dzień miesiąca. W takim przypadku testy zakończą się powodzeniem i niecommand1
zostaną wykonane. Zadanie jest uruchamiane w południe w dni, które mogą być ostatnim dniem miesiąca.Oryginalne polecenie:
Ma to kilka problemów:
[
.;
Bezpośrednio pothen
.%
jest specjalny w specyfikacjach zadań crona i musi być oznaczony jako\%
(patrzman 5 crontab
).fi
końcu nie ma finału, który pasowałby doif
.źródło
[ ... ] && command1
zamiastif...
polega na tym, że w dni, które nie są ostatnim dniem miesiąca, zadanie crona zakończy się niezerowym statusem wyjścia i może być konieczne zgłoszenie awarii . Używanie[ "$(...)" != 01 ] || command1
to kolejny sposób na uniknięcie problemu.;
międzythen
icommand1
."
albo'
(z wyjątkiem\
), znak procent%
uczyni cron przełamać linię na dwie części. To jeden ze zwykłych sposobów na niepowodzenie crona.Aby zaplanować ostatni dzień każdego miesiąca, można spróbować:
0 0 15,L * *
.źródło