¿Cómo creo un crontab a través de un script?

153

Necesito agregar un trabajo cron a través de un script que ejecuto para configurar un servidor. Actualmente estoy usando Ubuntu. Puedo usar crontab -epero eso abrirá un editor para editar el crontab actual. Quiero hacer esto programáticamente.

¿Es posible hacerlo?

gaurav
fuente
Si está buscando modificar o eliminar una entrada crontab, vea mi solución a continuación.
Brian Smith

Respuestas:

11

Los trabajos Cron generalmente se almacenan en un archivo por usuario en /var/spool/cron

Probablemente, lo más sencillo es crear un archivo de texto con el trabajo configurado, luego copiarlo en la carpeta de spool cron y asegurarse de que tenga los permisos correctos (600).

Jason Stelzer
fuente
19
Modificar los archivos directamente en / var / spool / cron está mal visto. De hecho, si mira los archivos allí, generalmente contendrán advertencias como "NO EDITE ESTE ARCHIVO" como la primera línea.
Jared
12
@Jared Aunque estoy bastante de acuerdo con la idea, decir que "está mal visto" no ayuda mucho. En lugar de eso, indique qué otro archivo debe editarse, o explique los riesgos de editar archivos manualmente. Estoy planeando crear algunos trabajos cron a través de la línea de comandos automatizada, y si editar este archivo es la única opción y sin efectos secundarios significativos, no veo por qué no debería usarlo.
Balmipour
47
Desplácese hacia abajo para obtener la respuesta real.
John Red
1
En mi opinión, esta respuesta es mucho mejor: stackoverflow.com/a/610860/2681752
galaux
2
Tomé este enfoque y lo lamenté. En RHEL, el directorio / var / spool / cron no es ejecutable en todo el mundo, por lo que los usuarios no pueden recorrer el directorio y editar sus archivos manualmente. Si hace que / var / spool / cron world sea ejecutable, su amigable administrador de sistemas local se enojará con usted, además, el cambio de permiso puede sobrescribirse si el paquete cronie alguna vez se reinstala o actualiza.
functionvoid
384

Aquí hay una línea que no usa / no requiere que el nuevo trabajo esté en un archivo:

(crontab -l 2>/dev/null; echo "*/5 * * * * /path/to/job -with args") | crontab -

Esto 2>/dev/nulles importante para que no reciba el no crontab for usernamemensaje que producen algunos * nixes si actualmente no hay entradas de crontab.

Joe Casadonte
fuente
14
Esta debería ser la respuesta aceptada. Solo necesito una forma ahora de verificar si la línea que pretendo agregar ya está allí o no ...
ChrisPrime
77
... oh, espera, así es cómo verificar si hay algo en el crontab de mi usuario antes de agregarlo con un script: stackoverflow.com/a/14451184/3686125
ChrisPrime
1
Si este script está pensado como un comando para ser repetido y modificar una tarea cron existente, podría ser bueno reemplazar la línea existente en crontab. Se pueden usar varios marcadores para controlar diferentes tareas cron (control-marker-1, control-marker-2, etc.): (crontab -l 2> / dev / null | grep -v control-marker-1; echo '* / 5 * * * * / ruta / al / trabajo -con args # control-marker-1') | crontab -
chef
77
Descubrí que esto estaba eliminando las entradas crontab existentes y también necesitaba usar un usuario diferente (root), así que utilicé lo siguiente para mantener las entradas existentes: echo -e "$(sudo crontab -u root -l)\n* * * * * echo hello > /home/danny/temp.log 2>&1" | sudo crontab -u root -Espero que esto ayude a alguien
Danny
60

Para los crontabs de usuario (incluida la raíz), puede hacer algo como:

crontab -l -u user | cat - filename | crontab -u user -

donde el archivo llamado "nombre de archivo" contiene elementos para agregar. También puede hacer manipulación de texto usando sedu otra herramienta en lugar de cat. Deberías usar elcrontab comando en lugar de modificar directamente el archivo.

Una operación similar sería:

{ crontab -l -u user; echo 'crontab spec'; } | crontab -u user -

Si está modificando o creando crontabs del sistema, estos pueden manipularse como lo haría con los archivos de texto normales. Se almacenan en los /etc/cron.d, /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthlydirectorios y en los archivos /etc/crontaby /etc/anacrontab.

Pausado hasta nuevo aviso.
fuente
Parecía prometedor pero al intentar el segundo enfoque (con echo), obtuve "crontab: error de uso: se debe especificar el nombre del archivo para reemplazarlo". La página de manual de Cron muestra la sintaxis como crontab [ -u user ] file, es decir, con un nombre de archivo obligatorio. ¿Hay algún truco para que acepte los datos canalizados?
Mark Berry
1
@MarkBerry: Perdón por eso. En una tubería, se debe usar un guión para indicar que la entrada es de stdin. Corregiré mi respuesta.
Pausado hasta nuevo aviso.
29

En Ubuntu y muchas otras distribuciones, solo puede poner un archivo en el /etc/cron.ddirectorio que contiene una sola línea con un crontab válido entrada . No es necesario agregar una línea a un archivo existente.

Si solo necesita algo para ejecutar diariamente, simplemente coloque un archivo /etc/cron.daily. Del mismo modo, también se puede soltar archivos en /etc/cron.hourly, /etc/cron.monthly, y /etc/cron.weekly.

IvanGoneKrazy
fuente
55
Pero debes ser root para hacer esto.
Keith
17

Una respuesta aún más simple a su pregunta sería:

echo "0 1 * * * /root/test.sh" | tee -a /var/spool/cron/root

Puede configurar cronjobs en servidores remotos de la siguiente manera:

#!/bin/bash
servers="srv1 srv2 srv3 srv4 srv5"
for i in $servers
  do
  echo "0 1 * * * /root/test.sh" | ssh $i " tee -a /var/spool/cron/root"
done

En Linux, la ubicación predeterminada del crontabarchivo es /var/spool/cron/. Aquí puede encontrar los crontabarchivos de todos los usuarios. Solo necesita agregar su entrada de cronjob al archivo del usuario respectivo. En el ejemplo anterior, el archivo crontab del usuario raíz se agrega con un cronjob para ejecutarse /root/test.shtodos los días a la 1 AM.

Ganesh Pathak
fuente
Eso estaría /var/spool/cron/crontabs/rooten Ubuntu.
Íhor Mé
17

Los archivos Crontab son simplemente archivos de texto y, como tales, pueden tratarse como cualquier otro archivo de texto. El propósito del crontabcomando es hacer que la edición de archivos crontab sea más segura. Cuando se edita a través de este comando, el archivo se verifica en busca de errores y solo se guarda si no hay ninguno.

crontab [path to file]se puede usar para especificar un crontab almacenado en un archivo. Al igual crontab -e, esto solo instalará el archivo si está libre de errores.

Por lo tanto, un script puede escribir directamente archivos de pestaña cron o escribirlos en un archivo temporal y cargarlos con el crontab [path to temp file]comando. Escribir directamente ahorra tener que escribir un archivo temporal, pero también evita la verificación de seguridad.

Cledoux
fuente
2
Para novatos como yo, tenga en cuenta que es crontab [path to file]... Esta fue definitivamente la mejor opción para mí, ya que permite un código más legible. Uso crontab para rastrear paquetes y cambiar el fondo de escritorio con el estado. Cuando no espero paquetes, no es necesario verificar cada hora. Es por eso que quería que el script editara automáticamente la frecuencia cron.
Rasmus
1
@Rasmus Eso suena como un guión increíble que me encantaría poder robar. ¿Alguna posibilidad de compartir a través de una esencia o similar?
cledoux
8

(No tengo suficiente reputación para comentar, así que estoy agregando como respuesta: siéntase libre de agregarlo como comentario junto a su respuesta)

El one-liner de Joe Casadonte es perfecto, excepto si corres conset -e , es decir, si su script está configurado para fallar en caso de error, y si todavía no hay cronjobs. En ese caso, el one-liner NO creará el cronjob, pero NO detendrá el script. El fracaso silencioso puede ser muy engañoso.

La razón es que crontab -lregresa con un 1código de retorno, causando el siguiente comando (elecho ) no se ejecute ... por lo tanto, el cronjob no se crea. Pero como se ejecutan como un subproceso (debido al paréntesis), no detienen el script.

(Curiosamente, si ejecuta el mismo comando nuevamente, funcionará: una vez que haya ejecutado crontab -una vez, crontab -laún no muestra nada, pero ya no devuelve un error (ya no recibe el no crontab for <user>mensaje). Entonces echose ejecuta el siguiente y se crea el crontab)

En cualquier caso, si corre con set -e, la línea debe ser:

(crontab -l 2>/dev/null || true; echo "*/5 * * * * /path/to/job -with args") | crontab -
Faria
fuente
Sí, este es aún más perfecto.
Yngve Sneen Lindal
7

Como corrección para aquellos que sugieren crontab -l | crontab -: esto no funciona en todos los sistemas. Por ejemplo, tuve que agregar un trabajo al crontab raíz en docenas de servidores que ejecutan una versión anterior SUSE (no pregunte por qué). Los antiguos SUSE anteponen líneas de comentarios a la salida de crontab -l, haciendo que crontab -l | crontab -no sean idempotentes (Debian reconoce este problema en la página de manual de crontab y parcheó su versión de Vixie Cron para cambiar el comportamiento predeterminado de crontab -l).

Para editar crontabs mediante programación en sistemas donde crontab -lagrega comentarios, puede intentar lo siguiente:

EDITOR=cat crontab -e > old_crontab; cat old_crontab new_job | crontab -

EDITOR=catle dice a crontab que lo use catcomo editor (no el vi predeterminado habitual), que no cambia el archivo, sino que lo copia en stdout. Esto aún podría fallar si crontab -espera una entrada en un formato diferente de lo que sale crontab -e. No intente reemplazar el final crontab -con crontab -e- no funcionará.

usuario2845840
fuente
4

Bueno, /etc/crontabsolo un archivo ASCII, así que lo más simple es

 echo "*/15 * * * *   root     date" >> /etc/crontab

que agregará un trabajo que le enviará un correo electrónico cada 15 minutos. Ajuste al gusto y pruebe a través degrep u otro medio si la línea ya se agregó para hacer que su script sea idempotente.

En Ubuntu et al, también puede colocar archivos en los /etc/cron.*que es más fácil de hacer y probar --- además no se mete con archivos de configuración (del sistema) como /etc/crontab.

Dirk Eddelbuettel
fuente
1
Creo que técnicamente crond no es necesario para monitorear los cambios en crontab, incluso si en realidad la mayoría de las implementaciones lo hacen, por lo que recomendaría una llamada a crontab -e después para pincharlo. crontab -e respeta la variable EDITOR si la memoria sirve, por lo que establecerla en / bin / true por el momento debería obligar a que se vuelva a leer el crontab.
Ulrich Schwarz
1
Es cierto, sin embargo, en cualquier sistema Linux reciente que crond sí lo hace , y ciertamente lo hace en la plataforma declarada del OP.
Dirk Eddelbuettel
Solo si eres root y quieres que el script se ejecute como root. Eso podría no ser deseable en el caso de los PO.
Keith
No es así, tengo muchas entradas no root en / etc / crontab. Usted 'simplemente' necesita sudo para agregar al archivo. De todos modos, como dije, también hay /etc/cron.*/ pero también debes ser root para escribir allí.
Dirk Eddelbuettel
2

Aquí se explica cómo modificar cron una entrada sin editar directamente el archivo cron (que está mal visto).

crontab -l -u <user> | sed 's/find/replace/g' | crontab -u <user> -

Si desea eliminar una entrada cron, use esto:

crontab -l -u <user> | sed '/find/d' | crontab -u <user> -

Me doy cuenta de que esto no es lo que Gaurav estaba pidiendo, pero ¿por qué no tener todas las soluciones en un solo lugar?

Brian Smith
fuente
1

He escrito una herramienta de implementación de crontab en python: https://github.com/monklof/deploycron

pip install deploycron

Instalar su crontab es muy fácil, esto fusionará el crontab en el crontab existente del sistema.

from deploycron import deploycron
deploycron(content="* * * * * echo hello > /tmp/hello")
monklof
fuente
1

Es un enfoque para agregar incrementalmente el trabajo cron:

  ssh USER_NAME@$PRODUCT_IP nohup "echo '*/2 * * * * ping -c2 PRODUCT_NAME.com >> /var/www/html/test.html' | crontab -u USER_NAME -"
Oleksii Kyslytsyn
fuente