GNU/Linux >> Linux Esercitazione >  >> Linux

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

Soluzione 1:

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

Questo è un wiki della comunità, se noti qualcosa di errato in questa risposta o hai ulteriori informazioni, modificalo.

Prima, terminologia di base:

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

Successivamente, informazioni su cron:

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

C'è un /etc/crontab a livello di sistema file, il /etc/cron.d la directory può contenere frammenti di crontab che vengono letti e attivati ​​anche da cron. Alcune distribuzioni Linux (per esempio, Red Hat) hanno anche /etc/cron.{hourly,daily,weekly,monthly} che sono 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 modifichi il file crontab con il comando crontab -e e salvalo, crond ne controlla la validità di base ma non garantisce che il tuo file crontab sia formato correttamente. C'è un file chiamato cron.deny che specificherà quali utenti non possono usare cron. Il cron.deny la posizione del file dipende dal sistema e può essere eliminata, 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 recupererà ed eseguirà le query precedenti.

dettagli crontab, come formulare un comando:

Un comando crontab è rappresentato da una singola riga. Non puoi usare \ per estendere un comando su più righe. L'hash (# ) rappresenta un commento che significa che qualsiasi cosa su quella riga viene ignorata da cron. Gli spazi bianchi iniziali e le righe vuote vengono ignorati.

Fai MOLTA attenzione quando usi la percentuale (% ) accedi al tuo comando. A meno che non siano sfuggiti a \% vengono convertiti in newline e tutto ciò che segue il primo % senza caratteri di escape viene passato al tuo comando su stdin.

Ci sono due formati per i file crontab:

  • Crontab 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
    
  • A livello di sistema /etc/crontab e /etc/cron.d frammenti

     # 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 utente specificato.

I primi 5 campi della riga rappresentano l'ora o le ore in cui il comando deve essere eseguito. Puoi utilizzare numeri o nomi di giorni/mesi, ove applicabile, nella specifica dell'ora.

  • I campi sono separati da spazi o tabulazioni.
  • Una virgola (, ) viene utilizzato 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 può essere combinato con elenchi, ad es. 1-3,9-12 che significa tra 1 e 3 poi tra 9 e 12.
  • Il / carattere può essere utilizzato per introdurre un passaggio, ad es. 2/5 che significa partire 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-59 per il campo dei minuti).
  • Gli intervalli e i passaggi possono essere combinati, ad es. */2 significa partire dal minimo per il campo pertinente quindi ogni 2 ad es. 0 per i minuti (0,2...58), 1 per i mesi (1,3 ... 11) ecc.

Debug dei comandi cron

Controlla la posta!

Per impostazione predefinita, cron invierà qualsiasi output dal comando all'utente con cui sta eseguendo il comando. Se non c'è output non ci sarà posta. Se desideri che cron invii la posta a un account diverso, puoi impostare la variabile di ambiente MAILTO nel file crontab, ad es.

[email protected]
1 2 * * * /path/to/your/command

Acquisisci tu stesso l'output

Puoi reindirizzare stdout e stderr in un file. La sintassi esatta per catturare l'output può variare a seconda della shell che cron sta usando. Ecco due esempi che salvano tutto l'output in un file in /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 log

Cron registra le sue azioni tramite syslog, che (a seconda della tua configurazione) spesso va a /var/log/cron o /var/log/syslog .

Se necessario, puoi filtrare le istruzioni cron con ad 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.

Verifica che cron sia in esecuzione

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

ps -ef | grep cron | grep -v grep

dovrebbe darti qualcosa come

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

o

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

Altrimenti riavvialo

/sbin/service cron start

o

/sbin/service crond start

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

cron esegue il tuo comando in un ambiente limitato.

È probabile che le variabili di ambiente disponibili siano molto limitate. In genere, otterrai solo poche variabili definite, come $LOGNAME , $HOME e $PATH .

Di particolare rilievo è il PATH è limitato a /bin:/usr/bin . La stragrande maggioranza dei problemi "il mio script cron non funziona" è causata 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 del tuo comando.

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

     PATH=/bin:/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 tuo comando con cwd ==$HOME

Indipendentemente da dove risieda il programma che esegui sul filesystem, la directory di lavoro corrente del programma quando cron lo esegue sarà la home directory dell'utente . Se accedi ai file nel tuo programma, dovrai tenerne conto se utilizzi percorsi relativi o (preferibilmente) utilizza solo percorsi completi ovunque, risparmiando a tutti un bel po' di 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 è possibile utilizzare 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 quell'utente.

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

  • Controlla che il nome del file non abbia un'estensione vedi run-parts
  • Assicurati che il file abbia i permessi di esecuzione.
  • Di' al sistema cosa usare durante l'esecuzione del tuo script (es. put #!/bin/sh in alto)

Bug relativi alla data di cron

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

Segni di percentuale, di nuovo

Per enfatizzare i consigli sui simboli di percentuale, ecco un esempio di ciò che cron fa con essi:

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

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

foo
bar
baz

Questo è particolarmente invadente quando si utilizza il date comando. Assicurati di evitare i simboli di percentuale

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

Attenti a Sudo

durante l'esecuzione come utente non root,

crontab -e

aprirà il crontab dell'utente, mentre

sudo crontab -e

aprirà il crontab dell'utente root. Non è consigliabile eseguire i comandi sudo in un cron job, quindi se stai tentando di eseguire un comando sudo nel cron di un utente, prova a spostare quel comando nel cron di root e rimuovi sudo dal comando.

Soluzione 2:

Debian Linux e le sue derivate (Ubuntu, Mint, ecc.) hanno alcune particolarità che potrebbero impedire l'esecuzione dei tuoi cron job; in particolare, i file in /etc/cron.d , /etc/cron.{hourly,daily,weekly,monthly} deve :

  • essere di proprietà di root
  • essere scrivibile solo da root
  • non essere scrivibile dal gruppo o da altri utenti
  • hanno un nome senza punti '.' o qualsiasi altro carattere speciale tranne '-' e '_' .

L'ultimo ferisce regolarmente gli utenti ignari; in particolare qualsiasi script in una di queste cartelle denominata whatever.sh , mycron.py , testfile.pl , ecc. non essere giustiziato, mai.

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

Vedi man cron per maggiori dettagli, se necessario.

Soluzione 3:

Se i tuoi cronjob smettono di funzionare, controlla che la tua password non sia scaduta., poiché una volta che lo è, tutti i cron job si interrompono.
Ci saranno messaggi in /var/log/messages simile a quello qui sotto che mostra problemi con l'autenticazione dell'utente:

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

Soluzione 4:

Orari non comuni e irregolari

Cron è tutto sommato 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 come "esegui command ogni 5 minuti" :

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

contro:

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

cosa che non sempre eseguire command ogni 7 minuti .

Ricorda che il file / carattere può essere utilizzato per introdurre un passaggio ma i passaggi non vanno a capo oltre la fine di una serie, ad es. */7 che corrisponde ogni 7 minuti dai minuti 0-59 cioè 0,7,14,21,28,35,42,49,56 ma tra un'ora e l'altra ci saranno solo 4 minuti tra i batch , dopo 00:56 una nuova serie inizia da 01:00 , 01:07 ecc. (e i batch non verranno eseguiti su 01:03 , 01:10 , 01:17 ecc.).

Cosa fare invece?

Crea più batch

Piuttosto che un singolo cron job, crea più batch che combinino 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 viene eseguito solo nelle 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 tuoi batch meno frequentemente

Anziché eseguire il tuo batch ogni 7 minuti, che è una pianificazione difficile da suddividere in più batch, eseguilo semplicemente ogni 10 minuti.

Avvia i tuoi 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 pianificati 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 in modo diverso e crea un cronjob che fallirà con grazia quando un'esecuzione precedente non è ancora terminata, ma che funzionerà diversamente. Vedi questa domanda e risposta:

* * * * * /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 grazia quando le condizioni non sono giuste)

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

In bash il seven-minute-job assomiglierebbe quindi a qualcosa di simile a:

#!/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 (tentare) di eseguire in sicurezza ogni minuto:

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

Un problema diverso, ma simile, sarebbe programmare l'esecuzione di un batch il primo lunedì di ogni mese (o il secondo mercoledì) ecc. Pianificare semplicemente l'esecuzione del batch ogni lunedì ed uscire quando la data non è compresa tra 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 (tentare) di eseguire in sicurezza ogni lunedì:

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

Non utilizzare cron

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

Soluzione 5:

Specifico per PHP

Se hai qualche cron job come:

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

E in caso di errori aspettati che ti vengano inviati, ma non -- controlla qui.

PHP per impostazione predefinita non invia errori a STDOUT. @vedi https://bugs.php.net/bug.php?id=22839

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

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

La prima impostazione ti consentirà di avere fatali come "Memory oops" e la seconda - per reindirizzarli tutti a STDERR. Solo dopo potrai dormire sonni tranquilli poiché tutto verrà inviato alla tua posta di root invece che solo registrato.


Linux
  1. Redis come cache:come funziona e perché usarlo

  2. Come posso rendere la sessione sudo un'ora e non pochi minuti in Ubuntu 10.04?

  3. perché sftp rmdir non funziona?

  4. Perché usiamo su - e non solo su?

  5. i flag sed e e g non funzionano insieme

Come scoprire se un pacchetto è installato o meno in Linux e Unix

Linux – Perché usiamo Su – e non solo Su?

Perché Scp è così lento e come renderlo più veloce?

Ubuntu – Crontab non funziona?

In che modo il lavoro a distanza e la pianificazione della continuità aziendale possono mitigare l'impatto del COVID-19 (Coronavirus)?

Come e perché usare Linux per installare Telnet