Cron co 5 minut i crontab przykłady krok po kroku
Cron co 5 minut, co godzinę i w dni robocze: crontab przykłady krok po kroku, pułapki 9-17, 31. dnia, znaku % i zmiany czasu, z wyliczonymi terminami.

288. Tyle razy na dobę uruchomi się zadanie zapisane jako */5 * * * *, czyli cron co 5 minut. Dwanaście razy na godzinę, w minutach 0, 5, 10 i tak dalej aż do 55. Wygląda to prosto, dopóki nie trzeba dopisać „ale tylko w godzinach pracy” albo „w ostatni dzień miesiąca”. Wtedy pięć pól crontaba zaczyna zachowywać się inaczej, niż podpowiada intuicja.
Poniżej jeden crontab budowany od pustego pliku do czterech zadań: kopia bazy w nocy, sprawdzanie kolejki co 5 minut w dni robocze, cotygodniowy raport i zadanie na początek miesiąca. Każdy wpis sprawdziłem w generatorze cron, który liczy najbliższe uruchomienia w czasie polskim. Przy każdym kroku jest też pułapka, na którą ten wpis wpadł albo prawie wpadł.
Pięć pól, zanim cokolwiek wpiszesz
Najpierw krótko, czym jest cron. To program działający w tle (dokumentacja nazywa go demonem, crond), który przegląda zapisane crontaby i dla każdego zadania sprawdza, czy ma ruszyć w bieżącej minucie. Crontaby użytkowników leżą w /var/spool/cron, a do tego dochodzą /etc/crontab i katalog /etc/cron.d. Restartować go po zmianie nie trzeba: zmienione pliki wczytuje sam. Stąd najmniejsza jednostka harmonogramu to jedna minuta. Zadania „co 30 sekund” zwykły crontab nie zapisze.
Linia crontaba to pięć pól czasu i polecenie. Kolejność się nie zmienia: minuta, godzina, dzień miesiąca, miesiąc, dzień tygodnia. Gwiazdka znaczy „każda wartość”. Zakresy i dopuszczalne wartości podaje dokumentacja crona w Linuksie (man 5 crontab):
| Pole | Wartości | Uwagi |
|---|---|---|
| minuta | 0-59 | */5 = co 5 minut |
| godzina | 0-23 | bez 24, północ to 0 |
| dzień miesiąca | 1-31 | 31 nie ma w każdym miesiącu |
| miesiąc | 1-12 | albo nazwy jan-dec |
| dzień tygodnia | 0-7 | 0 i 7 to niedziela, albo nazwy sun-sat |
Ukośnik to krok, przecinek to lista, myślnik to zakres. Tyle składni. Reszta to wnioski z tego, jak cron te pola łączy.
Cron co 5 minut i jego krewni
Większość pytań o crona sprowadza się do „co ile”. Tabela niżej zbiera najczęstsze odstępy, z liczbą uruchomień na dobę. Ostatnia kolumna mówi, kiedy wypadnie pierwsze uruchomienie, jeśli wpis zapiszesz o 10:02.
| Co ile | Wyrażenie | Na dobę | Po zapisie o 10:02 |
|---|---|---|---|
| co minutę | * * * * * | 1 440 | 10:03 |
| cron co 5 minut | */5 * * * * | 288 | 10:05 |
| co 15 minut | */15 * * * * | 96 | 10:15 |
| cron co godzinę | 0 * * * * | 24 | 11:00 |
| co 2 godziny | 0 */2 * * * | 12 | 12:00 |
| raz dziennie po północy | 5 0 * * * | 1 | 00:05 następnego dnia |
Zauważ jedną rzecz: */5 nie liczy pięciu minut od chwili zapisu. Liczy od pełnej godziny. Zapisany o 10:02 wpis odpali o 10:05, a nie o 10:07. Tak samo „0 */2” trafia w godziny parzyste (0, 2, 4...), a nie co dwie godziny od teraz.
I tu pierwsza niespodzianka. Co z odstępem, który nie dzieli 60? Wpis */35 * * * * wygląda jak „co 35 minut”, a działa w minutach 0 i 35. Generator pokazuje kolejne uruchomienia: 12:35, 13:00, 13:35, 14:00. Odstępy wychodzą na przemian 35 i 25 minut, bo krok działa tylko w obrębie jednego pola i zaczyna się od nowa co godzinę. Dokumentacja crona pisze o tym wprost: */35 to dwa uruchomienia na godzinę, nie „co 35 minut”.
Crontab przykłady od zera: cztery zadania na jednym serwerze
Projekt jest prosty: jeden serwer, jeden crontab, cztery zadania. Edytujesz go poleceniem crontab -e (otwiera edytor z VISUAL albo EDITOR i po zapisaniu sam instaluje zmiany), a podglądasz przez crontab -l. Krok po kroku, w kolejności dopisywania.
Krok 1. Kopia bazy co noc: 5 0 * * *
Pierwsza linia to zadanie nocne, pięć minut po północy:
5 0 * * * /opt/kopia/kopia-bazy.sh >> /var/log/kopia.log 2>&1
Dopisek na końcu przekierowuje wynik i błędy do pliku. Bez niego cron wysyła wynik pocztą do właściciela crontaba albo na adres z MAILTO. Pusty MAILTO wyłącza pocztę całkiem. Taki sam wzór, z $HOME/tmp/out, jest w przykładach w samej dokumentacji.
Dlaczego 00:05, a nie 02:30? Bo godzina 2 w nocy w Polsce to godzina zmiany czasu, o czym niżej. Pięć minut po północy jest bezpieczne przez cały rok.
Krok 2. Kolejka co 5 minut, tylko w godzinach pracy: */5 9-17 * * 1-5
Drugie zadanie ma sprawdzać kolejkę zamówień co 5 minut od poniedziałku do piątku, „od 9 do 17”. Wpis */5 9-17 * * 1-5 robi jednak coś trochę innego. Zakres 9-17 w polu godziny obejmuje całą godzinę 17, więc ostatnie uruchomienie dnia wypada o 17:55, nie o 17:00. Generator, zapytany od 16:52 w poniedziałek, pokazuje: 16:55, 17:00, 17:05, 17:10, 17:15. Dziewięć godzin po dwanaście uruchomień daje 108 dziennie, 540 w tygodniu.
Jeśli praca kończy się o 17:00 co do minuty, potrzebne są dwie linie: */5 9-16 * * 1-5 i osobno 0 17 * * 1-5. To wtedy 96 plus 1, czyli 97 uruchomień dziennie. Różnica wynosi 11 uruchomień dziennie i 55 w tygodniu, wszystkie między 17:05 a 17:55, kiedy w biurze już nikogo nie ma.
Krok 3. Raport w poniedziałek o 9:00: 0 9 * * 1
Trzecie zadanie jest najprostsze. Dzień tygodnia 1 to poniedziałek, a niedzielę można zapisać jako 0 albo 7: oba zapisy działają, co generator potwierdza dla 0 0 * * 7 (kolejne niedziele o północy). Zamiast cyfr da się też wpisać nazwy: 0 9 * * mon działa tak samo. Polskich skrótów („pon”) cron nie zna.
Tu pułapka czeka w poleceniu, nie w czasie. Znak procentu w poleceniu crona zamienia się w nową linię, a tekst po nim trafia do programu jako wejście. Raport wywołany z datą w nazwie pliku, np. date +%d, trzeba zapisać z ukośnikiem przed procentem: date +\%d. Bez tego polecenie urwie się w połowie, a w logu nie będzie jasnego komunikatu dlaczego.
Krok 4. Początek i koniec miesiąca: 0 0 1 * * i dlaczego nie 31
Czwarte zadanie ma ruszyć na początku miesiąca: 0 0 1 * *, czyli 1. dnia o północy. Działa w każdym miesiącu.
Pokusa, żeby zamknięcie miesiąca ustawić na 31., kończy się źle. 0 0 31 * * uruchomi się tylko w miesiącach, które mają 31 dni, a takich jest 7 w roku: styczeń, marzec, maj, lipiec, sierpień, październik i grudzień. W lutym, kwietniu, czerwcu, wrześniu i listopadzie zadanie po prostu się nie odpali. Cron nie ma w składni „ostatniego dnia miesiąca”, a zapis z literą L, znany z innych programów, wyrzuca błąd. Bezpieczne wyjście to zadanie 1. dnia o 00:00, które rozlicza poprzedni miesiąc.
Bilans: cztery linie, ile uruchomień w tygodniu
Po czterech krokach crontab ma cztery linie. Tabela pokazuje, ile razy w zwykłym tygodniu (bez zmiany czasu i bez przełomu miesiąca) uruchomi się każda z nich.
| Zadanie | Wyrażenie | W tygodniu | Na co uważać |
|---|---|---|---|
| kopia bazy | 5 0 * * * | 7 | przekierowanie wyniku do logu |
| kolejka zamówień | */5 9-17 * * 1-5 | 540 | ostatnie o 17:55 |
| raport | 0 9 * * 1 | 1 | % w poleceniu |
| start miesiąca | 0 0 1 * * | 0 albo 1 | nie 31. |
Około 98 % uruchomień (540 z 549) generuje jedna linia, ta co 5 minut. Jeśli serwer coś obciąża, to właśnie ona, i od niej warto zacząć, gdy w logach widać za dużo wpisów.
Dzień miesiąca LUB dzień tygodnia
Najbardziej zdradliwa reguła crona dotyczy dwóch pól dni. Gdy oba są ograniczone, czyli żadne nie jest gwiazdką, zadanie rusza, gdy pasuje którekolwiek z nich, a nie oba naraz. Przykład z dokumentacji: 30 4 1,15 * 5 to 4:30 rano 1. i 15. dnia miesiąca oraz w każdy piątek.
Ktoś, kto chciał „w piątki, które wypadają 1. albo 15.”, dostaje zadanie odpalane sześć albo siedem razy w miesiącu. W miesiącu zaczynającym się w niedzielę generator wypisuje kolejno: 1. (niedziela), 6. (piątek), 13. (piątek), 15. (niedziela), 20. (piątek). Czy da się zapisać „piątek i zarazem 13.”? W samym cronie nie. Trzeba sprawdzić datę w poleceniu albo w skrypcie.
Noc zmiany czasu w crontabie
W ostatnią niedzielę marca zegar przeskakuje z 2:00 na 3:00, a w ostatnią niedzielę października cofa się z 3:00 na 2:00. Dokumentacja crona mówi krótko: godziny, których nie ma, nigdy nie pasują, a godziny powtórzone uruchamiają zadanie dwa razy.
Kod demona cronie, jednej z implementacji crona w Linuksie, zachowuje się łagodniej dla zadań o stałej godzinie. Generator idzie za kodem, nie za skrótem z dokumentacji, i dla nocy zmiany czasu pokazuje:
| Wyrażenie | Noc w marcu | Noc w październiku |
|---|---|---|
| 30 2 * * * | nadrobione o 3:00 | 1 uruchomienie |
| */30 2 * * * | 0 uruchomień, przepadają | 4 uruchomienia: 2:00 i 2:30 dwa razy |
| 5 0 * * * | bez zmian | bez zmian |
Wniosek jest praktyczny: zadań, które nie mogą się powtórzyć ani wypaść, nie ustawia się między 2:00 a 2:59. Dlatego kopia w kroku 1 stoi na 00:05.
Lekcje z czterech linii
Pierwsza: krok zaczyna się od pełnej godziny, nie od chwili zapisu. */5 to minuty 0, 5, 10, a */35 to dwa uruchomienia na godzinę.
Druga: zakres godzin obejmuje całą ostatnią godzinę. 9-17 kończy się o 17:55.
Trzecia: dwa pola dni łączy LUB. Kto chce I, musi to sprawdzić w skrypcie.
Czwarta: środowisko crona to nie terminal. Dokumentacja podaje, że SHELL to /bin/sh, a HOME i LOGNAME pochodzą z /etc/passwd. Skrypt, który działa po wpisaniu w terminalu, w cronie może nie znaleźć programów, więc pełne ścieżki (/usr/bin/..., /opt/...) oszczędzają nerwów.
Piąta: procent w poleceniu i noc zmiany czasu. Obie rzeczy nie dają błędu przy zapisie, tylko złe działanie kilka tygodni później.
Retrospektywa: ten sam crontab, poprawiony
Gdyby pisać te cztery linie jeszcze raz, od razu z wnioskami, wyglądałyby tak:
MAILTO=""
5 0 * * * /opt/kopia/kopia-bazy.sh >> /var/log/kopia.log 2>&1
*/5 9-16 * * 1-5 /opt/sklep/kolejka.sh
0 17 * * 1-5 /opt/sklep/kolejka.sh
0 9 * * 1 /opt/raport/raport.sh > /var/log/raport-$(date +\%d).log 2>&1
0 0 1 * * /opt/ksiegowosc/zamkniecie-poprzedniego-miesiaca.sh
Pięć linii zadań zamiast czterech, bo „do 17:00” wymagało rozbicia. MAILTO pusty, bo wynik idzie do plików. Ani jednego zadania w godzinie 2. W skrócie: każdą z tych linii warto przed zapisaniem wkleić do generatora i zobaczyć pięć najbliższych terminów. Kilka sekund zamiast czekania do poniedziałku, żeby sprawdzić, czy raport naprawdę przyszedł.
Gdzie sprawdzić wpis, zanim trafi na serwer
Generator Cron buduje wyrażenie z listy (co N minut, dni robocze, raz w miesiącu) albo rozkłada gotowe na pola, tłumaczy je po polsku i wypisuje najbliższe uruchomienia w czasie polskim, łącznie z nocą zmiany czasu.
Przy okazji tego samego dnia powstały jeszcze dwa narzędzia: Regex Tester, który podświetla dopasowania wyrażeń regularnych, na przykład przy przeszukiwaniu logów z crona, oraz JWT Decoder do odczytu tokenu i sprawdzenia daty jego wygaśnięcia.
Inne narzędzia przydatne przy pracy na serwerze
Kalkulator Chmod - skrypt uruchamiany przez crona musi mieć prawo wykonania, a tu sprawdzisz, co znaczy 755 albo 700.
Generator .htaccess - przekierowanie na HTTPS i blokada plików .env na serwerze Apache.
Formatowanie JSON - czytelny zapis i walidacja plików konfiguracyjnych.
Generator Danych Testowych - fikcyjne rekordy do sprawdzenia skryptu, zanim zacznie działać na prawdziwej bazie.
Kodowanie Base64 - kodowanie i dekodowanie tekstu, np. nagłówka Basic Auth w skrypcie.
Generator SHA-256 - skrót SHA-256 i HMAC tekstu, np. do porównania wersji konfiguracji.
