Come posso dire a cron di eseguire un comando a giorni alterni (pari / dispari)


45

Quando configuri cron per eseguire un comando a giorni alterni utilizzando il campo "Giorno del mese", in questo modo:

1 22 */2 * * COMMAND

funziona ogni volta che il giorno del mese è dispari: 1,3,5,7,9 e così via.

Come posso configurare cron per l'esecuzione in giorni del mese che sono anche come 2,6,8,10 e così via (senza specificarlo letteralmente, il che è problematico poiché ogni mese ha un numero diverso di giorni nel mese)?

Risposte:


60

La sintassi che hai provato è in realtà ambigua. A seconda di quanti giorni sono nel mese, alcuni mesi verranno eseguiti in giorni dispari e altri in pari. Questo perché il modo in cui viene calcolato prende il numero totale di possibilità e le divide. È possibile ignorare questo comportamento strage specificando manualmente l'intervallo di giorni e utilizzando un numero pari o dispari di giorni. Poiché gli script dei giorni pari non verrebbero mai eseguiti il ​​31 ° giorno dei mesi più lunghi, non perdi nulla usando 30 giorni come base per i giorni pari e specificando specificamente di dividerlo come se ci fossero 31 giorni puoi forzare dispari -esecuzione giornaliera.

La sintassi sarebbe simile a questa:

# Will only run on odd days:
0 0 1-31/2 * * command

# Will only run on even days:
0 0 2-30/2 * * command

La tua preoccupazione per i mesi che non hanno lo stesso numero di giorni non è importante qui perché nessun mese ha PIÙ giorni di questo e per il povero febbraio, l'intervallo di date non corrisponderà mai all'ultimo giorno o due, ma non farà alcun male avendo elencato.

L'unico 'gotcha' per questo approccio è che se sei in un ciclo di giorni dispari, dopo mesi con 31 giorni il tuo comando verrà eseguito anche il primo del mese. Allo stesso modo se stai forzando un ciclo uniforme, ogni anno bisestile causerà un ciclo di tre giorni e la fine di febbraio. Non puoi davvero aggirare il fatto che qualsiasi modello regolare di "ogni altro giorno" non cadrà sempre nei giorni pari o dispari di ogni mese e in qualunque modo lo forzerai avrai una corsa extra o ti mancherà una corsa tra mesi con conteggi giornalieri non corrispondenti.


1
Grazie, ma cosa succederà in mesi come febbraio in cui hai solo 28 giorni? La star si prende davvero cura di questo - ma è davvero ambigua.
freddie,

3
@freddie: vedi la mia risposta modificata ... ma non è un problema perché i valori fuori range verranno semplicemente ignorati, non succederà nulla il 30 o il 31 febbraio. Mai. Puoi specificare manualmente con un elenco come 0,2,4...,30,32,34e non avrebbe importanza, i valori fuori intervallo non verrebbero mai abbinati.
Caleb,

1
Grazie! Capisco, grazie per te la risposta informativa!
freddie,

3
Sul server Ubuntu 8.04, sembra che la sintassi usando zero del giorno del mese non sia valida (giorno del mese errato). La seguente sintassi, tuttavia, è accettata:0 0 2-30/2 * * command

1
Anche a Fedora e RHEL 5,6,7 non piace 0 come giorno del mese. Come sottolineato dall'utente31053: 0 0 2-30/2 * * commandfunziona come previsto.
NoelProf,

2

Penso che una possibilità stia usando il giorno dell'anno, come questo:

# for odd days
test $(((`date +%j` % 2))) != 0 && command

# for even days
test $(((`date +%j` % 2))) == 0 && command

È testato per sistemi Unix e Linux.


Preferisco questa risposta perché salta il problema con il numero dispari di giorni con alcuni mesi. Comunque suggerisco la notazione in dollari invece i backtick:test $(($(date +%j) % 2)) == 0 && command
caligari

Ho esaminato che% j non è la data giuliana, quindi il miglior codice che evita la transizione di Capodanno deve essere calcolato con secondi:test $(($(date +%s) / 86400 % 2)) == 0 && command
caligari

Grazie per i commenti! La nostra proposta ha funzionato per noi come un fascino. Abbiamo usato questo schema per eseguire cron ogni giorno su nodi server diversi, tutti condividendo lo stesso crontab, ma lo script consente solo di eseguire lo script su uno di essi. Tuttavia, se dobbiamo renderlo più specifico, prenderemo in considerazione la tua proposta. Grazie!!!
Jordi,

1

Controlliamo ogni giorno se si tratta di un "altro" :-) ( bcprogramma richiesto)

0 0 * * * test $(echo `date +%s` / 86400 % 2 == 0 |bc) -eq 0 && command

(Non sono sicuro che il codice appaia correttamente. La date +%sparte è tra apostrofi posteriori.)


Questo funzionerà a giorni alterni ma non risponde alla domanda! Funzionerà ancora a volte nei giorni dispari a volte nei giorni pari a seconda del mese. Questo ha lo stesso risultato del codice nella domanda, stai arrivando al risultato facendo i tuoi calcoli sui secondi dall'epoca. Funziona in giorni pari fin dall'epoca ma non nei giorni pari del nostro calendario.
Caleb,

1

In generale, lo eseguivo ogni giorno e lo script usa la logica per determinare se dovrebbe essere eseguito oggi.

Creare un semplice file di stato che indichi l'ultima esecuzione e quindi il compairing funzionerebbe molto facilmente.

Se deve essere eseguito su origini diverse, rendilo dipendente dall'argomento.

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.