¿Cómo puedo crear programáticamente un nuevo trabajo cron?

129

Quiero poder agregar programáticamente un nuevo trabajo cron, ¿cuál es la mejor manera de hacerlo?

Según mi investigación , parece que podría volcar el crontab actual y luego agregar uno nuevo, volviéndolo a crontab:

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

¿Hay una mejor manera?

davidmytton
fuente
2
Su solución parece buena.
Craig S
En Solaris simplemente elimine el guión para el último crontab. Puede agregar un grep para evitar agregar una línea ya allí.
lacroix1547
Posible duplicado de Cómo crear un trabajo cron usando Bash
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
las llaves en lugar de paréntesis lo harán sin generar un proceso. Asegúrese de mantener espacios alrededor de las llaves, {...; }.
Jay Winston

Respuestas:

-25

Siempre me ha funcionado bien.

Debería considerar un script un poco más sofisticado que puede hacer tres cosas.

  1. Añadir una línea crontab; asegurando que no existía. Agregar cuando ya existe es malo.

  2. Elimina la línea crontab. Tal vez solo advertencia si no existiera.

  3. Una combinación de las dos características anteriores para reemplazar la línea crontab.

S.Lott
fuente
78
Él pregunta cómo y tú le dices qué.
Cerin
1
¿Qué pasa si el usuario aún no tiene un crontab?
Maxim Egorushkin
132

La mejor manera si está ejecutando como root, es soltar un archivo en /etc/cron.d

si usa un administrador de paquetes para empaquetar su software, simplemente puede colocar archivos en ese directorio y se interpretan como si fueran crontabs, pero con un campo adicional para el nombre de usuario, por ejemplo:

Nombre del archivo: /etc/cron.d/per_minute

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

MarkR
fuente
55
Solo asegúrese de que la versión de cron en uso sea compatible con /etc/cron.d/. La mayoría de las distribuciones modernas de Linux sí.
sleske
8
Esta es la solución más simple y elegante. Seguro supera tener que analizar y editar un crontab existente con otras entradas no relacionadas.
Cerin
13
Una advertencia potencial a esto es la frecuencia con la que cron recoge nuevas adiciones a esta carpeta (una vez por hora). Si espera que su trabajo comience a ejecutarse de inmediato, tenga cuidado.
JonathanK
66
@ JonathanK, ¿sabes si se le puede pedir a cron que vuelva a escanear /etc/cron.d/*? ¡Es difícil saber si algo funciona si uno tiene que esperar una hora para verificar!
halfer
44
¿Cómo deben establecerse los permisos para este archivo? chmod + x /etc/cron.d/per_minute?
giò
101

La solución de OP tiene un error, puede permitir que las entradas se agreguen dos veces, use a continuación para solucionarlo.

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
JohnZ
fuente
55
Esta es realmente una solución mejor si no se describe. Asegura que el comando no se agregue dos veces a crontab.
Bufke
2
Esto no es una buena solución para el problema de la entrada duplicada. ¿Qué pasa si se agrega otra línea a crontab mientras tanto?
hmn
66
Para garantizar la unicidad, justo sortantes uniq, por ejemplo:(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
mway
66
No hay necesidad de uniq. Use la -uopción en sort.
papiro
66
cómo evitar que no haya crontab para el usuario cuando edito crontab por primera vez.
wyx
23

Para agregar algo a cron

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

Para eliminar esto de cron

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

la esperanza ayudaría a alguien

usuario3865482
fuente
Esto es exactamente lo que estaba buscando, simplemente agregaría esto: | grep -v '^ #' | filtrar los comentarios
Tjunkie
2
En realidad, no debería necesitarlo 2>&1 | grep -v "no crontab"porque cuando no hay crontab, la línea de salida crontab: no crontab for...se envía a stderr. No hay razón para capturar esa salida, enviarla a stdout y luego filtrarla usando grep. Si su objetivo es evitar ver crontab: no crontab for...en su salida, entonces use 2> /dev/null | sort.....
matty
6

Si está planeando hacerlo en un escenario de ejecución única para simplemente jugar algo, eche un vistazo a 'at'

Christian Witts
fuente
6

Simplemente cambie el editor al comando tee:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e
Renato Tambellini
fuente
3
Cuidado: esto borra cualquier entrada existente.
starfry
5

Suponiendo que ya hay una entrada en su crontab, el siguiente comando debería funcionar relativamente bien. Tenga en cuenta que la $CMDvariable solo está ahí para facilitar la lectura. Ordenar antes de filtrar duplicados es importante, porque uniqsolo funciona en líneas adyacentes.

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

Si actualmente tiene un crontab vacío, recibirá el siguiente error para stderr:

no crontab for user

Si desea evitar esto, puede agregar un poco de complejidad y hacer algo como esto:

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

La mayoría de las soluciones aquí son para agregar líneas al crontab. Si necesita más control, querrá poder controlar todo el contenido del crontab.

Puede usar tuberías para hacer esto de manera elegante.

Para reescribir completamente el crontab, haga

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

Esto debería ser fácil de combinar con otras respuestas descritas aquí como

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

O, si tiene el contenido en un archivo, es aún más simple

cat <file> |crontab -
Eldamir
fuente
3

Aquí hay otra forma de una línea, que evita duplicados

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

Y aquí hay una manera de responder a JohnZ y evitar no crontab for usermensajes, o si necesita operar en un set -euentorno de tipo y no puede hacer que nada devuelva una falla (en cuyo caso la 2>/dev/nullparte es opcional):

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

O si desea dividir las cosas para que sean más legibles:

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

O, opcionalmente, elimine cualquier referencia a your_command (por ejemplo: si la programación ha cambiado, solo desea que se cronometre una vez). En este caso ya no necesitamos uniq(bonificación adicional, el orden de inserción también se conserva):

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
fuente
2

man crontab también es útil:

CRONTAB (1)

NOMBRE

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

SINOPSIS

   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
fuente
3
La parte que dice "reemplazar crontab de stdin" es en realidad la mitad de una respuesta :-)
Grodriguez
2

Agregando a la respuesta de JohnZ, aquí está la sintaxis para programar como root si eres un sudoer:

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

Esto verificará para asegurarse de que su comando no exista antes de agregarlo.

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

Salud.

Ezra Obiwale
fuente
0

La conexión de stdout en crontabno instaló el nuevo crontab para mí en macOS, por lo que encontré esta solución en su lugar, usando el teeeditor en un sub shell:

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

Si desea que la tarea se ejecute como usuario:

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

Si desea que la tarea se ejecute con privilegios:

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

y verifique la tarea (con o sin 'sudo'):

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

También puede agregar sus tareas a /etc/cron.*/

vitaly.v.ch
fuente
-2

También puede editar el archivo de texto de la tabla cron directamente, pero su solución parece perfectamente aceptable.

Alex Fort
fuente
1
Sería receloso de esto debido a las preocupaciones sobre la posibilidad de que las ediciones concurrentes causen corrupción de archivos. El uso del comando crontab de la línea de comandos debería evitar ese problema.
Craig S
Craig, sin más investigación no estaría seguro de que la versión de la línea de comandos es atómica y segura para las condiciones de carrera. Probablemente "bastante seguro" de todos modos.
tuomassalo
"Editar el archivo directamente" no es factible sin acceso a la raíz (siempre que pueda averiguar dónde vive el archivo crontab del usuario y cómo asegurarse de que el demonio cron reciba correctamente sus cambios), y "editar" programáticamente parece ser la pregunta. quiere consejos sobre en primer lugar.
tripleee