Abstrakcyjny
Prawidłowy kod powinien być:
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
Wywołaj ten skrypt, end_of_month.sh
a wywołanie w cron jest po prostu:
00 12 28-31 * * /path/to/script/end_of_month.sh command
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:
- Brakuje zamknięcia
fi
.
- Potrzebuje miejsca między
[
i poniżej `
.
- Jest zdecydowanie zaleca się użycie $ (...) zamiast
`…`
.
- Ważne jest, aby używać cudzysłowów wokół rozszerzeń takich jak
"$(…)"
- Jest dodatkowy
;
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 przyjmuje tomorrow
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):
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
Wywołaj ten skrypt, end_of_month.sh
a wywołanie w cron jest po prostu:
00 12 28-31 * * /path/to/script/end_of_month.sh command
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ń:
- Cron dzieli linię poleceń na dowolną,
%
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:
$ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
Command will be executed....