Comment puis-je créer par programme une nouvelle tâche cron?

129

Je veux pouvoir ajouter par programme un nouveau travail cron, quelle est la meilleure façon de le faire?

D'après mes recherches , il semble que je pourrais vider le crontab actuel, puis en ajouter un nouveau, en le renvoyant dans crontab:

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

Y a-t-il un meilleur moyen?

Davidmytton
la source
2
Votre solution semble bonne.
Craig S
Sur Solaris, supprimez simplement le tiret du dernier crontab. Vous pouvez ajouter un grep pour éviter d'ajouter une ligne déjà présente.
lacroix1547
Copie possible de Comment créer une tâche cron à l'aide de Bash
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
des accolades au lieu de parenthèses le feront sans engendrer de processus. Assurez-vous de garder des espaces autour des accolades, {...; }.
Jay Winston

Réponses:

-25

Cela a toujours bien fonctionné pour moi.

Vous devriez envisager un script légèrement plus sophistiqué qui peut faire trois choses.

  1. Ajoutez une ligne crontab; assurant qu'il n'existait pas. Ajouter quand il existe déjà est mauvais.

  2. Retirez la ligne crontab. Peut-être seulement un avertissement s'il n'existait pas.

  3. Une combinaison des deux fonctionnalités ci-dessus pour remplacer la ligne crontab.

S.Lott
la source
78
Il demande comment et tu lui dis quoi?
Cerin
1
Que faire si l'utilisateur n'a pas encore de crontab?
Maxim Egorushkin
132

La meilleure façon si vous exécutez en tant que root, est de déposer un fichier dans /etc/cron.d

si vous utilisez un gestionnaire de paquets pour empaqueter votre logiciel, vous pouvez simplement placer des fichiers dans ce répertoire et ils sont interprétés comme s'il s'agissait de crontabs, mais avec un champ supplémentaire pour le nom d'utilisateur, par exemple:

Nom de fichier: /etc/cron.d/per_minute

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

MarkR
la source
5
Assurez-vous simplement que la version de cron utilisée prend en charge /etc/cron.d/. La plupart des distributions Linux modernes le font.
sleske
8
C'est la solution la plus simple et la plus élégante. Bien sûr, il vaut mieux analyser et éditer un crontab existant avec d'autres entrées non liées.
Cerin
13
Une mise en garde potentielle à cela est la fréquence à laquelle cron prend les nouveaux ajouts à ce dossier (une fois par heure). Si vous vous attendez à ce que votre travail commence tout de suite, méfiez-vous.
JonathanK
6
@JonathanK, savez-vous si cron peut être invité à effectuer une nouvelle analyse /etc/cron.d/*? Il est difficile de savoir si quelque chose fonctionne s'il faut attendre une heure pour vérifier!
halfer
4
comment définir les perms pour ce fichier? chmod + x /etc/cron.d/per_minute?
giò le
101

La solution d'OP a un bogue, elle pourrait permettre d'ajouter deux fois des entrées, utilisez ci-dessous pour corriger.

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
JohnZ
la source
5
C'est en fait une solution meilleure sinon décrite. Cela garantit que la commande n'est pas ajoutée deux fois à crontab.
Bufke
2
Ce n'est guère une bonne solution pour le problème de l'entrée en double. Et si une autre ligne était ajoutée à crontab entre-temps?
hmn le
6
Pour garantir l'unicité, juste sortavant uniq, par exemple:(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
mway
6
Pas besoin de uniq. Utilisez l' -uoption sur sort.
papiro
6
comment éviter l' absence de crontab pour l'utilisateur lors de la première édition de crontab.
wyx
23

Pour ajouter quelque chose à cron

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

Pour supprimer cela de cron

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

l'espoir aiderait quelqu'un

user3865482
la source
C'est exactement ce que je cherchais je voudrais juste ajouter ceci: | grep -v '^ #' | pour filtrer les commentaires
Tjunkie
2
En fait, vous ne devriez pas en avoir besoin 2>&1 | grep -v "no crontab"car lorsqu'il n'y a pas de crontab, la ligne de sortie crontab: no crontab for...est envoyée à stderr. Il n'y a aucune raison de capturer cette sortie, de l'envoyer à stdout, puis de la filtrer à l'aide de grep. Si votre objectif est d'éviter de voir crontab: no crontab for...dans votre sortie, utilisez 2> /dev/null | sort.....
matty le
6

Si vous prévoyez de le faire pour un scénario unique pour simplement faire quelque chose, jetez un œil à 'at'

Christian Witts
la source
6

Changez simplement l'éditeur en commande tee:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e
Renato Tambellini
la source
3
Attention - cela efface toutes les entrées existantes.
starfry
5

En supposant qu'il existe déjà une entrée dans votre crontab, la commande suivante devrait fonctionner relativement bien. Notez que la $CMDvariable n'est là que pour la lisibilité. Le tri avant de filtrer les doublons est important, car uniqne fonctionne que sur les lignes adjacentes.

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

Si vous avez actuellement un crontab vide, vous recevrez l'erreur suivante à stderr:

no crontab for user

Si vous voulez éviter cela, vous pouvez ajouter un peu de complexité et faire quelque chose comme ceci:

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

La plupart des solutions ici sont pour ajouter des lignes à la crontab. Si vous avez besoin de plus de contrôle, vous voudrez pouvoir contrôler tout le contenu de la crontab.

Vous pouvez utiliser la tuyauterie pour le faire assez élégamment.

Pour réécrire complètement le crontab, faites

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

Cela devrait être facile à combiner avec d'autres réponses décrites ici comme

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

Ou, si vous avez le contenu dans un fichier, c'est encore plus simple

cat <file> |crontab -
Eldamir
la source
3

Voici une autre méthode unilatérale, qui évite les doublons

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

Et voici un moyen de faire la réponse de JohnZ et d'éviter le no crontab for usermessage, ou si vous devez fonctionner dans un set -euenvironnement de type et que rien ne peut renvoyer un échec (auquel cas la 2>/dev/nullpartie est facultative):

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

Ou si vous voulez diviser les choses pour qu'elles soient plus lisibles:

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

Ou supprimez éventuellement toutes les références à votre_commande (ex: si le planning a changé, vous ne voulez qu'il soit créé une seule fois). Dans ce cas, nous n'avons plus besoin uniq(bonus supplémentaire, l'ordre d'insertion est également conservé):

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 -
rogerdpack
la source
2

man crontab est également utile:

CRONTAB (1)

NOM

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

SYNOPSIS

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

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

   crontab -l [user] - list crontab for user
vitaly.v.ch
la source
3
La partie qui dit "remplacer crontab de stdin" est en fait une demi-réponse :-)
Grodriguez
2

En plus de la réponse de JohnZ, voici la syntaxe à planifier en tant que root si vous êtes un sudoer:

(sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -
BuvinJ
la source
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');
RafaSashi
la source
1

Cela vérifierait que votre commande n'existe pas déjà avant de l'ajouter.

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

À votre santé.

Ezra Obiwale
la source
0

L' crontabinstallation de stdout dans n'a pas installé le nouveau crontab pour moi sur macOS, j'ai donc trouvé cette solution à la place, en utilisant l' teeéditeur dans un sous-shell:

(EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)
Simon Hänisch
la source
0

Si vous souhaitez que la tâche s'exécute en tant qu'utilisateur:

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

Si vous souhaitez que la tâche s'exécute avec des privilèges:

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

et vérifier la tâche (avec ou sans 'sudo'):

crontab -l | sed '/^$/d; /#/d'
ajcg
la source
-1

vous pouvez également ajouter vos tâches à /etc/cron.*/

vitaly.v.ch
la source
-2

Vous pouvez également éditer le fichier texte de la table cron directement, mais votre solution semble parfaitement acceptable.

Alex Fort
la source
1
Je me méfierais de cela en raison des préoccupations concernant le risque de modifications simultanées causant la corruption de fichiers. L'utilisation de la commande crontab en ligne de commande devrait éviter ce problème.
Craig S
Craig, sans plus de recherche, je ne serais pas sûr que la version en ligne de commande soit atomique et sans danger pour la course. Probablement "tout à fait sûr" de toute façon.
tuomassalo
"Modifier le fichier directement" n'est pas faisable sans un accès root (à condition que vous puissiez déterminer où se trouve le fichier crontab de l'utilisateur et comment vous assurer que le démon cron reçoit correctement vos modifications), et "éditer" par programme semble être la question veut des conseils en premier lieu.
tripleee