Perché il mio crontab non funziona e come posso risolverlo?


226

Questa è una domanda canonica sull'uso di cron & crontab.

Sei stato indirizzato qui perché la community è abbastanza sicura che la risposta alla tua domanda possa essere trovata di seguito. Se la tua domanda non ha una risposta di seguito, le risposte ti aiuteranno a raccogliere informazioni utili alla community. Queste informazioni dovrebbero essere modificate nella domanda originale.

La risposta per " Perché il mio crontab non funziona e come posso risolverlo? 'può essere visto sotto. Questo indirizza il cronsistema con il crontab evidenziato.


2
Questo è un enorme inganno di motivi per cui crontab non funziona su AskUbuntu.
Dan Dascalescu il

1
@DanDascalescu Sembra che Eric abbia bisogno di ottenere più rappresentante
Sono la persona più stupida

1
Ho appena aderito a Server Fault SE (quindi solo 101 rappresentanti), ma mi piacerebbe dare a questa domanda un -1 !! Questa domanda è stata fatta solo per ottenere un rappresentante? @IamtheMostStupidPerson Sono totalmente d'accordo con te ...
Holyprogrammer

L'ideologia occidentale in questi padawan di 13 anni è sia manuale che accecante, come una supernova. Per rispondere a entrambe le tue domande: sì, l'ho fatto per il rappresentante, e sì, Eric ha bisogno di ottenere più reputazione. Di quanta più rappresentante ho bisogno ?? Di Più. youtu.be/IaDt9T7BF38?t=262
Eric Leschinski

Risposte:


317

Come risolvere tutti i tuoi problemi / problemi relativi a crontab (Linux)


Questa è una wiki della comunità , se noti qualcosa di errato con questa risposta o hai ulteriori informazioni, ti preghiamo di modificarlo.


Primo, terminologia di base:

  • cron (8) è il demone che esegue i comandi pianificati.
  • crontab (1) è il programma utilizzato per modificare i file dell'utente crontab (5).
  • crontab (5) è un file per utente che contiene le istruzioni per cron (8).

Successivamente, educazione su cron:

Ogni utente su un sistema può avere il proprio file crontab. La posizione dei file crontab utente e root dipendono dal sistema ma sono generalmente inferiori /var/spool/cron.

Esiste un /etc/crontabfile a livello di sistema , la /etc/cron.ddirectory può contenere frammenti crontab che sono anche letti e gestiti da cron. Alcune distribuzioni Linux (ad esempio, Red Hat) hanno anche /etc/cron.{hourly,daily,weekly,monthly}quali directory, script all'interno dei quali verranno eseguiti ogni ora / giorno / settimana / mese, con privilegio di root.

root può sempre usare il comando crontab; agli utenti regolari può essere concesso o meno l'accesso. Quando si modifica il file crontab con il comando crontab -ee lo si salva, crond lo verifica per la validità di base ma non garantisce che il file crontab sia formato correttamente. C'è un file chiamato cron.denyche specifica quali utenti non possono usare cron. Il cron.denypercorso del file dipende dal sistema e può essere eliminato, il che consentirà a tutti gli utenti di utilizzare cron.

Se il computer non è acceso o il demone crond non è in esecuzione e la data / ora per l'esecuzione di un comando è passata, crond non rileverà ed eseguirà le query passate.

particolari crontab, come formulare un comando:

Un comando crontab è rappresentato da una singola riga. Non è possibile utilizzare \per estendere un comando su più righe. Il #segno hash ( ) rappresenta un commento, il che significa che qualsiasi cosa su quella linea viene ignorata da cron. Gli spazi iniziali e le righe vuote vengono ignorati.

Fai molta attenzione quando usi il %segno percentuale ( ) nel tuo comando. A meno che non vengano salvati \%, vengono convertiti in newline e tutto ciò che segue il primo non-escape %viene passato al tuo comando su stdin.

Esistono due formati per i file crontab:

  • Crontabs dell'utente

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  *   command to be executed
    
  • Sistema ampio /etc/crontabe /etc/cron.dframmenti

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  * user-name  command to be executed
    

Si noti che quest'ultimo richiede un nome utente. Il comando verrà eseguito come l'utente nominato.

I primi 5 campi della riga rappresentano i tempi in cui il comando deve essere eseguito. È possibile utilizzare numeri o nomi di giorno / mese ove applicabili nelle specifiche dell'ora.

  • I campi sono separati da spazi o schede.
  • Una virgola ( ,) viene utilizzata per specificare un elenco, ad esempio 1,4,6,8, che significa eseguire a 1,4,6,8.
  • Gli intervalli sono specificati con un trattino ( -) e possono essere combinati con elenchi, ad esempio 1-3,9-12, che significa tra 1 e 3, quindi tra 9 e 12.
  • Il /personaggio può essere usato per introdurre un passaggio, ad es. 2/5, che significa iniziare da 2 poi ogni 5 (2,7,12,17,22 ...). Non vanno oltre la fine.
  • Un asterisco ( *) in un campo indica l'intero intervallo per quel campo (ad es. 0-59Per il campo dei minuti).
  • Intervalli e fasi possono essere combinati, ad esempio */2significa partire dal minimo per il campo pertinente, quindi ogni 2 ad esempio 0 per minuti (0,2 ... 58), 1 per mesi (1,3 ... 11) ecc.

Debug dei comandi cron

Controlla la posta!

Di default cron invierà qualsiasi output dal comando all'utente su cui sta eseguendo il comando. Se non c'è output non ci sarà posta. Se vuoi che cron invii la posta a un altro account, puoi impostare la variabile d'ambiente MAILTO nel file crontab ad es

MAILTO=user@somehost.tld
1 2 * * * /path/to/your/command

Cattura l'output tu stesso

È possibile reindirizzare stdout e stderr a un file. La sintassi esatta per catturare l'output può variare a seconda di quale shell cron sta usando. Ecco due esempi che salvano tutto l'output in un file su /tmp/mycommand.log:

1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1

Guarda i registri

Cron registra le sue azioni tramite syslog, che (a seconda della configurazione) spesso passa a /var/log/crono /var/log/syslog.

Se necessario, puoi filtrare le istruzioni cron con es

grep CRON /var/log/syslog 

Ora che abbiamo esaminato le basi di cron, dove sono i file e come usarli, diamo un'occhiata ad alcuni problemi comuni.

Controlla che cron sia in esecuzione

Se cron non è in esecuzione, i tuoi comandi non saranno programmati ...

ps -ef | grep cron | grep -v grep

dovresti prenderti qualcosa del genere

root    1224   1  0 Nov16 ?    00:00:03 cron

o

root    2018   1  0 Nov14 ?    00:00:06 crond

In caso contrario, riavviarlo

/sbin/service cron start

o

/sbin/service crond start

Potrebbero esserci altri metodi; usa ciò che la tua distribuzione fornisce.

cron esegue il comando in un ambiente limitato.

Le variabili di ambiente disponibili sono probabilmente molto limitate. In genere, si otterrà solo poche variabili definite, come ad esempio $LOGNAME, $HOMEe $PATH.

Di particolare nota è il PATHè limitato a /bin:/usr/bin. La stragrande maggioranza dei problemi "il mio cron script non funziona" sono causati da questo percorso restrittivo . Se il tuo comando si trova in una posizione diversa, puoi risolverlo in un paio di modi:

  1. Fornisci il percorso completo per il tuo comando.

    1 2 * * * /path/to/your/command
    
  2. Fornire un PERCORSO adatto nel file crontab

    PATH=/usr:/usr/bin:/path/to/something/else
    1 2 * * * command 
    

Se il tuo comando richiede altre variabili d'ambiente puoi definirle anche nel file crontab.

cron esegue il comando con cwd == $ HOME

Indipendentemente da dove risiede il programma che si esegue sul filesystem, l'attuale directory di lavoro del programma quando cron viene eseguito sarà la home directory dell'utente . Se accedi ai file nel tuo programma, dovrai tenerne conto se utilizzi percorsi relativi o (preferibilmente) utilizzi ovunque percorsi completamente qualificati e risparmi a tutti molta confusione.

L'ultimo comando nel mio crontab non viene eseguito

Cron generalmente richiede che i comandi vengano terminati con una nuova riga. Modifica il tuo crontab; vai alla fine della riga che contiene l'ultimo comando e inserisci una nuova riga (premi invio).

Controlla il formato crontab

Non puoi usare un crontab in formato crontab utente per / etc / crontab o i frammenti in /etc/cron.d e viceversa. Un crontab formattato dall'utente non include un nome utente nella sesta posizione di una riga, mentre un crontab formattato dal sistema include il nome utente ed esegue il comando come tale utente.

Ho messo un file in /etc/cron.{hourly,daily,weekly,monthly} e non funziona

  • Controlla che il nome del file non abbia un'estensione vedi parti di esecuzione
  • Assicurarsi che il file disponga delle autorizzazioni di esecuzione.
  • Indica al sistema cosa usare quando esegui il tuo script (es. Metti #!/bin/shin alto)

Cron bug relativi alla data

Se la tua data è stata recentemente modificata da un aggiornamento utente o di sistema, fuso orario o altro, allora crontab inizierà a comportarsi in modo irregolare e mostrerà bizzarri bug, a volte funzionanti, a volte no. Questo è il tentativo di crontab di provare a "fare quello che vuoi" quando il tempo cambia da sotto di esso. Il campo "minuto" diventerà inefficace dopo la modifica dell'ora. In questo scenario, sarebbero accettati solo asterischi. Riavvia cron e riprova senza collegarti a Internet (quindi la data non ha la possibilità di reimpostare su uno dei server dell'ora).

Segni percentuali, di nuovo

Per enfatizzare i consigli sui segni di percentuale, ecco un esempio di cosa fa cron con loro:

# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz

creerà il file ~ / cron.out contenente le 3 righe

foo
bar
baz

Ciò è particolarmente invadente quando si utilizza il datecomando. Assicurati di sfuggire ai segni di percentuale

* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"

Potrebbe anche essere necessario menzionare nella sezione "accesso limitato" che LD_LIBRARY_PATH potrebbe aver bisogno di avere ulteriori directory impostate nel caso in cui l'attività cron non riesca a causa dell'incapacità di trovare librerie condivise.
DavidJ,

nota che puoi persino scrivere qualcosa del genere: 35 1,5-23 / 2 * * * do_something invece di 35,1,5,7,9, .. * * * Inoltre questo crontab.guru traduce le voci che fai linguaggio umano.
Dennis Nolte,

1
La cattura dell'output non funziona per me, potrebbe essere a causa della shell sh. Penso che questo sia più portatile: ... /path/to/your/command >/tmp/mycommand.log 2>&1
chus

questo ha funzionato per me:sudo apt-get install postfix
jmunsch il

cron job dipende anche da quanto è pesante il file? Dato che ho eseguito un semplice ciao mondo in Python con cron, ha funzionato. Ma il mio secondo codice era un po 'pesante e normalmente funziona, ma con cron non fornisce alcun output nel file.
Devendra Bhat,

22

Debian Linux e il suo derivato (Ubuntu, Mint, ecc.) Presentano alcune peculiarità che potrebbero impedire l'esecuzione dei cron job; in particolare, i file in /etc/cron.d, /etc/cron.{hourly,daily,weekly,monthly}devono:

  • essere di proprietà di root
  • si può scrivere solo per root
  • non essere scrivibile dal gruppo o da altri utenti
  • avere un nome senza punti "." o qualsiasi altro carattere speciale tranne '-' e '_'.

L'ultimo fa male regolarmente agli utenti ignari; in particolare qualsiasi script in una di queste cartelle denominate whatever.sh, mycron.py, testfile.pl, ecc sarà non essere eseguito, mai.

Nella mia esperienza, questo particolare punto è stato di gran lunga il motivo più frequente di un cronjob non eseguito su Debian e derivati.

Vedi man cronper maggiori dettagli, se necessario.


19

Se i tuoi cronjob smettono di funzionare, controlla che la tua password non sia scaduta. Da allora, tutti i processi cron si interrompono.
Ci saranno messaggi /var/log/messagessimili a quello qui sotto che mostrano problemi con l'autenticazione dell'utente:

(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)


2
Ho appena ricevuto anche questo (messaggio di errore file / var / log / syslog per me). Nel mio caso una scatola DigitalOcean che, al momento della creazione, reimposta la password di root (facoltativamente) su un'altra, e apparentemente fino a quando non entri lì e la cambi, tutti i lavori cron non vengono eseguiti. Bummer. Fix è qualcosa di similesudo -u root passwd
rogerdpack

12

Pianificazioni non comuni e irregolari

Cron è tutto considerato uno scheduler molto semplice e la sintassi non consente facilmente a un amministratore di formulare pianificazioni leggermente più insolite.

Considera il seguente lavoro che normalmente verrebbe spiegato "esegui commandogni 5 minuti" :

*/5 * * * * /path/to/your/command

contro:

*/7 * * * * /path/to/your/command

che non funziona semprecommand ogni 7 minuti .

Ricorda che il /personaggio può essere usato per introdurre un passaggio ma che i passaggi non vanno oltre la fine di una serie, ad esempio */7che corrisponde ogni 7 minuti dai minuti, 0-59 ovvero 0,7,14,21,28,35,42,49, 56 ma tra un'ora e la successiva ci saranno solo 4 minuti tra lotti , dopo 00:56una nuova serie inizia 01:00, 01:07ecc (e lotti non verrà eseguito su 01:03, 01:10, 01:17ecc).


Cosa fare invece?

Crea più batch

Invece di un singolo processo cron, creare più batch che combinano il risultato nella pianificazione desiderata.

Ad esempio, per eseguire un batch ogni 40 minuti (00:00, 00:40, 01:20, 02:00 ecc.) Creare due batch, uno che viene eseguito due volte nelle ore pari e il secondo che esegue solo le ore dispari:

# The following lines create a batch that runs every 40 minutes i.e.

# runs on   0:00, 0:40,        02:00, 02:40         04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command

# runs on               01:20,               03:20,       etc to 23:20
20 1/2 * * * /path/to/your/command

# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.

Esegui i batch meno frequentemente

Invece di eseguire il batch ogni 7 minuti, che è una pianificazione difficile da suddividere in più batch, è sufficiente eseguirlo invece ogni 10 minuti.

Avvia i batch più frequentemente (ma impedisce l'esecuzione simultanea di più batch)

Molte pianificazioni dispari si evolvono perché i tempi di esecuzione del batch aumentano / fluttuano e quindi i batch vengono programmati con un po 'di margine di sicurezza aggiuntivo per evitare che le successive esecuzioni dello stesso batch si sovrappongano e vengano eseguite contemporaneamente.

Invece, pensa diversamente e crea un cronjob che fallirà con grazia quando una corsa precedente non è ancora terminata, ma che funzionerà diversamente. Vedi queste domande e risposte :

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job 

Ciò avvierà quasi immediatamente una nuova esecuzione una volta completata la precedente esecuzione di / usr / local / bin / frequent_cron_job.

Avvia i tuoi batch più frequentemente (ma esci con garbo quando le condizioni non sono giuste)

Poiché la sintassi cron è limitata, è possibile decidere di inserire condizioni e logica più complesse nel lavoro batch stesso (o in uno script wrapper attorno al lavoro batch esistente). Ciò ti consente di utilizzare le funzionalità avanzate dei tuoi linguaggi di scripting preferiti, di commentare il tuo codice e di prevenire costrutti difficili da leggere nella voce crontab stessa.

In bash seven-minute-jobsembrerebbe qualcosa del tipo:

#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated

if [ ! -f /tmp/lastrun ] ; then
    touch /tmp/lastrun
fi

if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
     # The minimum interval of 7 minutes between successive batches hasn't passed yet.
    exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF

Che puoi quindi tranquillamente (tentare) di eseguire ogni minuto:

* * * * * /path/to/your/seven-minute-job

Un problema diverso, ma simile sarebbe per pianificare un batch per eseguire il primo Lunedi di ogni mese (o il secondo Mercoledì) ecc Basta programmare il batch per eseguire ogni Lunedi e uscire quando la data non è né tra il 1 ° o 7 ° e il giorno della settimana non è lunedì.

#!/bin/bash
# first-monday-of-the-month-housekeeping-job

# exit if today is not a Monday (and prevent locale issues by using the day number) 
if [ $(date +%u) != 1 ] ; then
  exit 0
fi

# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
  exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#EOF

Che puoi quindi tranquillamente (tentare) di eseguire ogni lunedì:

0 0 * * 1 /path/to/your/first-monday-of-the-month-housekeeping-job

Non usare cron

Se le tue esigenze sono complesse, potresti prendere in considerazione l'uso di un prodotto più avanzato progettato per eseguire pianificazioni complesse (distribuite su più server) e che supporti trigger, dipendenze di lavoro, gestione degli errori, tentativi e monitoraggio dei tentativi, ecc. Il gergo del settore sarebbe "enterprise" " pianificazione dei lavori e / o" automazione del carico di lavoro ".


8

specifici per PHP

Se hai un lavoro cron come:

php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log

E in caso di errori si aspettano che ti vengano inviati, ma non lo fanno - controlla questo.

PHP di default non invia errori a STDOUT. @see https://bugs.php.net/bug.php?id=22839

Per risolvere questo problema, aggiungi in php.ini di cli o nella tua linea (o nel tuo wrapper bash per PHP) questi:

  • --define display_startup_errors = 1
  • --define display_errors = 'stderr'

La prima impostazione ti permetterà di avere fatali come 'Memory oops' e la seconda - per reindirizzarli tutti a STDERR. Solo dopo aver dormito bene, tutto verrà inviato alla posta di root invece che appena registrato.


2
Quel rapporto di errore è stato chiuso nel 2007 con lo stato della patch aggiunto ai rami PHP 5.2+. Sei sicuro che sia necessario? Ho appena provato su PHP 5.4 e sembra funzionare bene. (È comunque necessario per PHP 4).
Xeoncross

@Xeoncross vedi data di risposta :)
gaRex

1
Sì, questo è ciò che mi ha confuso da quando hai risposto nel 2013 e il biglietto era tornato nel '07.
Xeoncross

0

Aggiungendo la mia risposta da qui per completezza e aggiungendo un'altra risorsa potenzialmente utile:

L' cronutente ha un diverso $PATHda te:

Un problema frequente che gli utenti presentano con le crontabvoci è che dimenticano che cronviene eseguito in modo diverso environmentrispetto a come fanno gli utenti connessi. Ad esempio, un utente crea un programma o uno script nella sua $HOMEdirectory e immette il seguente comando per eseguirlo:

$ ./certbot ... 

Il comando viene eseguito perfettamente dalla sua riga di comando. L'utente quindi aggiunge quel comando al suo crontab, ma scopre che non funziona:

*/10 * * * * ./certbot ....

Il motivo dell'errore in questo caso è che la ./posizione crondell'utente è diversa rispetto a quella dell'utente connesso. Cioè, environmentè diverso! Il PERCORSO fa parte di environment, ed è generalmente diverso per l' cronutente. A complicare questo problema è che environmentfor cronnon è lo stesso per tutte le distribuzioni * nix e ci sono più versioni dicron

Una soluzione semplice a questo particolare problema è fornire cronall'utente una specifica di percorso completa nella crontabvoce:

0 22 * * * /path/to/certbot .....

Qual è l' cronutente environment?

In alcuni casi, potrebbe essere necessario conoscere le environmentspecifiche complete per cronil nostro sistema (o potremmo essere solo curiosi). Cos'è environmentper l' cronutente e in cosa differisce dalla nostra? Inoltre, potremmo avere bisogno di conoscere la environmentdi un altro cronutente - rootper esempio ... qual è l' rootutente di environmentutilizzare cron? Un modo per imparare questo è chiedere crondi dirci:

  1. Crea uno script di shell nella tua home directory ( ~/) come segue (o con l'editor di tua scelta):
$ nano ~/envtst.sh
  1. Immettere quanto segue nell'editor, dopo aver effettuato la regolazione per il proprio sistema / utente:
#!/bin/sh 
/bin/echo "env report follows for user "$USER >> /home/you/envtst.sh.out 
/usr/bin/env >> /home/you/envtst.sh.out 
/bin/echo "env report for user "$USER" concluded" >> /home/you/envtst.sh.out
/bin/echo " " >> /home/you/envtst.sh.out
  1. Salvare il file, chiudere l'editor e impostare le autorizzazioni per i file come eseguibili.
$ chmod a+rx ~/envtst.sh
  1. Esegui lo script appena creato e rivedi l'output /home/you/envtst.sh.out. Questo output mostrerà il tuo ambiente attuale come $USERhai effettuato l'accesso come:
$ ./envtst.sh $$ cat /home/you/envtst.sh.out
  1. Apri crontabper la modifica:
$ crontab -e -u root
  1. Inserisci la seguente riga nella parte inferiore del tuo crontab:
* * * * *  /home/you/envtst.sh >> /home/you/envtst.sh.err 2>&1

RISPOSTA: Il file di output /home/you/envtst.sh.outconterrà un elenco di environment"user cron root". Una volta che lo sai, modifica la crontabvoce di conseguenza.

Non riesco a specificare il programma di cui ho bisogno nella mia crontabvoce:

La voce di programma per crontabè ovviamente definita in man crontabe dovresti leggerla. Tuttavia, leggere man crontabe comprendere il programma sono due cose diverse. E tentativi ed errori su una specifica di pianificazione possono diventare molto noiosi. Fortunatamente, c'è una risorsa che può aiutare: il guru del crontab. . Inserisci le specifiche del tuo programma e questo spiegherà il programma in una semplice lingua inglese.

Infine, e rischiando di essere ridondanti con una delle altre risposte qui, non rimanere intrappolati nel pensare che sei limitato a una singola crontabvoce perché hai un lavoro da pianificare. Sei libero di utilizzare tutte le crontabvoci necessarie per ottenere il programma di cui hai bisogno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.