Come posso creare a livello di programmazione un nuovo cron job?


129

Voglio essere in grado di aggiungere programmaticamente un nuovo cron job, qual è il modo migliore per farlo?

Dalla mia ricerca , sembra che potrei scaricare l'attuale crontab e quindi aggiungerne uno nuovo, riportandolo in crontab:

(crontab -l ; echo "0 * * * * wget -O - -q http://www.example.com/cron.php") | crontab -

C'è un modo migliore?


2
La tua soluzione sembra buona.
Craig S

Su Solaris è sufficiente rimuovere il trattino per l'ultimo crontab. Puoi aggiungere un grep per evitare di aggiungere una linea già lì.
lacroix1547


le parentesi graffe invece delle parentesi lo faranno senza generare un processo. Assicurati di mantenere spazi attorno alle parentesi graffe, {...; }.
Jay Winston,

Risposte:


-25

Ha sempre funzionato bene per me.

Dovresti considerare uno script leggermente più sofisticato che può fare tre cose.

  1. Aggiungi una linea crontab; assicurando che non esisteva. Aggiungere quando esiste già è male.

  2. Rimuovi la linea crontab. Forse avvertendo solo se non esistesse.

  3. Una combinazione delle due funzioni precedenti per sostituire la linea crontab.


78
Chiede come e tu gli dici cosa?
Cerin,

1
Cosa succede se l'utente non ha ancora un crontab?
Maxim Egorushkin,

132

Il modo migliore se si esegue come root, è di rilasciare un file in /etc/cron.d

se usi un gestore di pacchetti per impacchettare il tuo software, puoi semplicemente impostare i file in quella directory e questi vengono interpretati come se fossero crontab, ma con un campo aggiuntivo per il nome utente, ad esempio:

Nome del file: /etc/cron.d/per_minute

Soddisfare: * * * * * root /bin/sh /home/root/script.sh


5
Assicurati solo che la versione di cron in uso supporti /etc/cron.d/. La maggior parte delle moderne distribuzioni Linux lo fanno.
sleske,

8
Questa è la soluzione più semplice ed elegante. Sicuramente i beat devono analizzare e modificare un crontab esistente con altre voci non correlate.
Cerin,

13
Un potenziale avvertimento a questo è la frequenza con cui cron raccoglie nuove aggiunte a questa cartella (una volta all'ora). Se ti aspetti che il tuo lavoro inizi a correre subito, fai attenzione.
JonathanK,

6
@JonathanK, ti capita di sapere se a cron può essere chiesto di ripetere la scansione /etc/cron.d/*? È difficile sapere se qualcosa funziona se si deve aspettare un'ora per controllare!
halfer

4
come dovrebbero essere impostati i permessi per questo file? chmod + x /etc/cron.d/per_minute?
giò,

101

La soluzione di OP ha un bug, potrebbe consentire l'aggiunta di voci due volte, utilizzare di seguito per risolvere.

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -

5
Questa è in realtà una soluzione migliore se non descritta. Assicura che il comando non venga aggiunto due volte a crontab.
Bufke,

2
Questa non è certo una buona soluzione per il problema della voce duplicata. E se nel frattempo fosse stata aggiunta un'altra riga a crontab?
hmn

6
Per garantire l'unicità, poco sortprima uniq, ad esempio:(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
mway

6
Non c'è bisogno di uniq. Usa l' -uopzione su sort.
papiro,

6
come evitare nessun crontab per l'utente quando modifico per la prima volta crontab.
wyx,

23

Per aggiungere qualcosa a cron

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -

Per rimuovere questo da cron

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | grep -v hupChannel.sh |  sort | uniq | crontab -

la speranza aiuterebbe qualcuno


Questo è esattamente quello che stavo cercando, aggiungerei semplicemente questo: | grep -v '^ #' | per filtrare i commenti
Tjunkie,

2
In realtà non dovresti aver bisogno 2>&1 | grep -v "no crontab"perché quando non c'è crontab, la linea di output crontab: no crontab for...viene inviata a stderr. Non c'è motivo di catturare quell'output, inviarlo a stdout e quindi filtrarlo usando grep. Se il tuo obiettivo è quello di evitare di vedere crontab: no crontab for...nell'output, quindi utilizzare 2> /dev/null | sort.....
matty

6

Se hai intenzione di farlo per uno scenario run-once solo per scommettere qualcosa, dai un'occhiata a 'at'


6

Cambia semplicemente l'editor in tee command:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e

3
Attenzione: questo cancella tutte le voci esistenti.
Starfry,

5

Supponendo che ci sia già una voce nel tuo crontab, il seguente comando dovrebbe funzionare relativamente bene. Nota che la $CMDvariabile è lì solo per leggibilità. L'ordinamento prima di filtrare i duplicati è importante, perché uniqfunziona solo su linee adiacenti.

CMD='wget -O - -q http://www.example.com/cron.php"'
(crontab -l ; echo "0 * * * * $CMD") | sort | uniq | crontab -

Se al momento hai un crontab vuoto, riceverai il seguente errore a stderr:

no crontab for user

Se vuoi evitare questo, puoi aggiungere un po 'di complessità e aggiungere qualcosa come questo:

(crontab -l ; echo "0 * * * * $CMD") 2>&1 | sed "s/no crontab for $(whoami)//"  | sort | uniq | crontab -

5

La maggior parte delle soluzioni qui sono per l'aggiunta di linee al crontab. Se hai bisogno di maggiore controllo, ti consigliamo di controllare l'intero contenuto del crontab.

Puoi usare le tubazioni per farlo in modo abbastanza elegante.

Per riscrivere completamente il crontab, fare

echo "2 2 2 2 2 /bin/echo foobar" |crontab -

Questo dovrebbe essere facile da combinare con altre risposte descritte qui come

crontab -l | <something> | tee |crontab -

Oppure, se hai i contenuti in un file, è ancora più semplice

cat <file> |crontab -

3

Ecco un altro modo da una riga, che evita i duplicati

(crontab -l 2>/dev/null | fgrep -v "*/1 *  *  *  * your_command"; echo "*/1 *  *  *  * your_command") | crontab -

Ed ecco un modo per fare la risposta di JohnZ ed evitare no crontab for usermessaggi, o se devi operare in un set -euambiente di tipo e non puoi avere nulla restituire un errore (nel qual caso la 2>/dev/nullparte è facoltativa):

( (crontab -l 2>/dev/null || echo "")  ; echo "0 * * * * your_command") | sort -u - | crontab -

O se vuoi dividere le cose in modo che siano più leggibili:

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
(echo "$preceding_cron_jobs" ; echo "$new_job") | sort - | uniq - | crontab -

Oppure rimuovi facoltativamente qualsiasi riferimento a tuo_comando (es: se la pianificazione è cambiata, vuoi che sia mai stata cronizzata una sola volta). In questo caso non abbiamo più bisogno uniq(bonus aggiuntivo, anche l'ordine di inserzione viene conservato):

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
preceding_cron_jobs=$(echo "$preceding_cron_jobs" | grep -v your_command )
(echo "$preceding_cron_jobs" ; echo "$new_job") | crontab -

2

man crontab è anche utile:

CRONTAB (1)

NOME

   crontab - manipulate per-user crontabs (Dillon's Cron)

SINOSSI

   crontab file [-u user] - replace crontab from file

   crontab - [-u user] - replace crontab from stdin

   crontab -l [user] - list crontab for user

3
La parte che dice "sostituisci crontab da stdin" è in realtà una mezza risposta :-)
Grodriguez,

2

Aggiungendo alla risposta di JohnZ, ecco la sintassi per pianificare come root se sei un sudoer:

(sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -

1
function cronjob_exists($command){

    $cronjob_exists=false;

    exec('crontab -l', $crontab);


    if(isset($crontab)&&is_array($crontab)){

        $crontab = array_flip($crontab);

        if(isset($crontab[$command])){

            $cronjob_exists=true;

        }

    }
    return $cronjob_exists;
}

function append_cronjob($command){

    if(is_string($command)&&!empty($command)&&cronjob_exists($command)===FALSE){

        //add job to crontab
        exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output);


    }

    return $output;
}

    append_cronjob('* * * * * curl -s http://localhost/cron/test.php');

1

Questo verificherebbe per assicurarsi che il tuo comando non esista già prima di aggiungerlo.

crontab -l 2>/dev/null | grep -q '/path/to/script' || echo "5 * * * * /path/to/script" | crontab -

Saluti.


0

Piping stdout in crontabnon ha installato il nuovo crontab per me su macOS, quindi ho trovato questa soluzione, usando l' teeeditor in una sub shell:

(EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)

0

Se si desidera che l'attività venga eseguita come utente:

crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | crontab -

Se si desidera eseguire l'attività con i privilegi:

sudo crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | sudo crontab -

e controlla l'attività (con o senza 'sudo'):

crontab -l | sed '/^$/d; /#/d'


-2

È inoltre possibile modificare direttamente il file di testo della tabella cron, ma la soluzione sembra perfettamente accettabile.


1
Ne sarei diffidente a causa delle preoccupazioni sulla possibilità di modifiche simultanee che causano la corruzione dei file. L'uso del comando crontab da riga di comando dovrebbe evitare questo problema.
Craig S

Craig, senza ulteriori ricerche non sarei sicuro che la versione da riga di comando sia atomica e sicura per le condizioni di gara. Probabilmente "abbastanza sicuro" comunque.
tuomassalo,

La "modifica diretta del file" non è possibile senza l'accesso root (a condizione che tu possa capire dove vive il file crontab dell'utente e come assicurarsi che il demone cron riceva correttamente le tue modifiche), e la "modifica" programmatica sembra essere la domanda vuole un consiglio in primo luogo.
triplo
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.