¿Cómo crear un trabajo cron usando Bash automáticamente sin el editor interactivo?

395

¿Tiene crontab un argumento para crear trabajos cron sin usar el editor (crontab -e)? Si es así, ¿cuál sería el código para crear un cronjob a partir de un script Bash?

Raúl Roa
fuente
55
Lamentablemente, la mayoría de las respuestas principales aquí solo muestran cómo modificar crontab, aunque de manera razonablemente segura, pero creo que en general es el enfoque incorrecto. Mejor, más seguro y más simple es colocar un archivo en {{cron.d}}, y (actualmente) hay respuestas de bajo voto que explican cómo hacerlo si mira hacia abajo.
gregmac

Respuestas:

539

Puede agregar al crontab de la siguiente manera:

#write out current crontab
crontab -l > mycron
#echo new cron into cron file
echo "00 09 * * 1-5 echo hello" >> mycron
#install new cron file
crontab mycron
rm mycron

Explicación de la línea de Cron

* * * * * "command to be executed"
- - - - -
| | | | |
| | | | ----- Day of week (0 - 7) (Sunday=0 or 7)
| | | ------- Month (1 - 12)
| | --------- Day of month (1 - 31)
| ----------- Hour (0 - 23)
------------- Minute (0 - 59)

Fuente nixCraft .

dogbane
fuente
14
Debería usar tempfile o mktemp
Paweł Polewicz
166
(crontab -l; echo "00 09 * * 1-5 echo hola") | crontab -
Edo
32
(crontab -l ; echo "00 09 * * 1-5 echo hello") | crontab -- más fácil de copiar la ropa de Edo
WBAR
8
Sugeriría cambiar eso ;con &&una protección contra el caso si crontab -lfalla. entonces, como:(crontab -l && echo "0 0 0 0 0 some entry") | crontab -
MacUsers
12
@MacUsers, crontab -lfalla si no hay crontab, por lo que el uso &&hace imposible que el script agregue la primera entrada al crontab.
JPhi1618
312

Es posible que pueda hacerlo sobre la marcha

crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab -

crontab -lenumera los trabajos crontab actuales, lo catimprime, echoimprime el nuevo comando y crontab -agrega todo el material impreso al archivo crontab. Puedes ver el efecto haciendo un nuevo crontab -l.

TheBonsai
fuente
3
gracias, ¿podría explicar la sintaxis o señalar una URL que lo explique?
sitios
99
crontab -lenumera los trabajos crontab actuales, lo catimprime, echoimprime el nuevo comando y crontab -agrega todo el material impreso al archivo crontab. Puede ver el efecto haciendo un nuevocrontab -l
nha
3
Funciona de maravilla para mí. Si el usuario no tiene un crontab existente, verá no crontab for <username>, pero funciona de todos modos.
Fazy
21
no funciona en mi instancia de Amazon EC2. En cambio, (crontab -l ; echo "00 09 * * 1-5 echo hello") | crontab -funciona.
Stéphane Bruckert
11
Esto parece un candidato para un UUcatA .
ceving
86

Este más corto no requiere un archivo temporal, es inmune a múltiples inserciones y le permite cambiar la programación de una entrada existente.

Digamos que tienes estos:

croncmd="/home/me/myfunction myargs > /home/me/myfunction.log 2>&1"
cronjob="0 */15 * * * $croncmd"

Para agregarlo al crontab, sin duplicación:

( crontab -l | grep -v -F "$croncmd" ; echo "$cronjob" ) | crontab -

Para eliminarlo del crontab sea cual sea su horario actual:

( crontab -l | grep -v -F "$croncmd" ) | crontab -

Notas:

  • grep -F coincide con la cadena literalmente, ya que no queremos interpretarla como una expresión regular
  • También ignoramos la programación del tiempo y solo buscamos el comando. De esta manera; el horario se puede cambiar sin el riesgo de agregar una nueva línea al crontab
MoonCactus
fuente
@moeseth: ¿puedes elaborar?
MoonCactus
deberías probarlo en tu computadora
moeseth 01 de
2
@moeseth: Obviamente lo intenté en mi computadora (Linux). No sugeriría cosas aleatorias que no funcionen: /
MoonCactus
2
Por cierto, 27 personas no pueden estar equivocadas (a partir de hoy). Entonces, describa por qué no funciona para su configuración, para que podamos ayudarlo.
MoonCactus
2
Puede ser un problema de OSX.
Moeseth
40

Gracias a todos por su ayuda. Juntando lo que encontré aquí y en otros lugares, se me ocurrió esto:

El código

command="php $INSTALL/indefero/scripts/gitcron.php"
job="0 0 * * 0 $command"
cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -

No pude descubrir cómo eliminar la necesidad de las dos variables sin repetirme.

commandobviamente es el comando que quiero programar. jobtoma $commandy agrega los datos de programación. Necesitaba ambas variables por separado en la línea de código que hace el trabajo.

Detalles

  1. Crédito a duckyflip, uso esta pequeña cosa de redireccionamiento ( <(*command*)) para convertir la salida de crontab -len entrada para el fgrepcomando.
  2. fgrepluego filtra cualquier coincidencia de $command( -vopción), sin distinción entre mayúsculas y minúsculas ( -iopción).
  3. Nuevamente, la pequeña cosa de redireccionamiento ( <(*command*)) se usa para convertir el resultado nuevamente en entrada para el catcomando.
  4. El catcomando también recibe echo "$job"(se explica por sí mismo), nuevamente, mediante el uso de la cosa de redireccionamiento ( <(*command*)).
  5. Por lo tanto, la salida filtrada crontab -ly la simple echo "$job", combinada, se canalizan ('|') crontab -para finalmente escribirse.
  6. ¡Y todos vivieron felices por siempre!

En una palabra:

Esta línea de código filtra cualquier trabajo cron que coincida con el comando, luego escribe los trabajos cron restantes con el nuevo, actuando efectivamente como una función "agregar" o "actualizar". Para usar esto, todo lo que tiene que hacer es intercambiar los valores de las variables commandy job.

Stoutie
fuente
55
Para el beneficio de otros que leen, la ventaja de este enfoque es que puede ejecutarlo varias veces sin preocuparse por las entradas duplicadas en el crontab (a diferencia de todas las otras soluciones). Eso se debe a lafgrep -v
aleemb
55
Si prefiere la forma tradicional de canalizar de izquierda a derecha, reemplace la última línea con: crontab -l | fgrep -i -v "$command" | { cat; echo "$job"; } | crontab -l
Antoine Lizée
1
@ AntoineLizée, tu respuesta tiene "l" extra al final, que no debería estar allí.
Henry
26

EDITAR (sobrescritura fija):

cat <(crontab -l) <(echo "1 2 3 4 5 scripty.sh") | crontab -
duckyflip
fuente
Esto reemplazará cualquier contenido de crontab
TheBonsai
1
@TheBonsai oh veo, me fijo ahora por lo que debe anexar el nuevo comando al contenido crontab existentes
duckyflip
3
Tenga en cuenta que la sustitución del proceso de Bash traga errores. Si crontab -lfalla, pero crontab -tiene éxito, su crontab será de una sola línea.
ceving
13

Ha habido muchas buenas respuestas sobre el uso de crontab, pero no se menciona un método más simple, como el uso cron.

El uso cronaprovecharía los archivos y directorios del sistema ubicados en /etc/crontab, /etc/cron.daily,weekly,hourlyo /etc/cron.d/:

cat > /etc/cron.d/<job> << EOF
SHELL=/bin/bash 
PATH=/sbin:/bin:/usr/sbin:/usr/bin 
MAILTO=root HOME=/  
01 * * * * <user> <command>
EOF

En este ejemplo anterior, creamos un archivo /etc/cron.d/, proporcionamos las variables de entorno para que el comando se ejecute correctamente y proporcionamos userel comando y el commandpropio. Este archivo no debe ser ejecutable y el nombre solo debe contener alfanuméricos y guiones (más detalles a continuación).

Sin embargo, para dar una respuesta completa, veamos las diferencias entre crontabvs cron/crond:

crontab -- maintain tables for driving cron for individual users

Para aquellos que desean ejecutar el trabajo en el contexto de su usuario en el sistema, el uso crontabpuede tener mucho sentido.

cron -- daemon to execute scheduled commands

Para aquellos que usan la administración de la configuración o desean administrar trabajos para otros usuarios, en cuyo caso deberíamos usar cron.

Un extracto rápido de las páginas de manual le ofrece algunos ejemplos de qué hacer y qué no hacer:

/ etc / crontab y los archivos en /etc/cron.d deben ser propiedad de root, y no deben ser grupales ni de otro tipo. A diferencia del área de spool, los archivos bajo /etc/cron.d o los archivos bajo /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly y /etc/cron.monthly también pueden ser enlaces simbólicos, siempre que tanto el enlace simbólico como el archivo al que apunta sean propiedad de root. Los archivos bajo /etc/cron.d no necesitan ser ejecutables, mientras que los archivos bajo /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly y /etc/cron.monthly sí, como son ejecutados por run-parts (ver run-parts (8) para más información).

Fuente: http://manpages.ubuntu.com/manpages/trusty/man8/cron.8.html

Administrar crons de esta manera es más fácil y más escalable desde la perspectiva del sistema, pero no siempre será la mejor solución.

Mike Mackintosh
fuente
1
Vale la pena mencionar que <job>no debe incluir una extensión de archivo.
jww
7

Es probable que esté automatizando esto, y no desea que se agregue un solo trabajo dos veces. En ese caso, use:

__cron="1 2 3 4 5 /root/bin/backup.sh"
cat <(crontab -l) |grep -v "${__cron}" <(echo "${__cron}")

Esto solo funciona si estás usando BASH. No conozco la shsintaxis correcta de DASH ( ).

Actualización: esto no funciona si el usuario aún no tiene un crontab. Una forma más confiable sería:

(crontab -l ; echo "1 2 3 4 5 /root/bin/backup.sh") | sort - | uniq - | crontab - 

Alternativamente, si su distribución lo admite, también podría usar un archivo separado:

echo "1 2 3 4 5 /root/bin/backup.sh" |sudo tee /etc/crond.d/backup

Los encontré en otra pregunta SO .

kvz
fuente
¿Usar sh en lugar de bash tal vez?
kvz
Todavía estoy sh: 1: Syntax error: "(" unexpectedusando sh .
Batandwa
Esto solo funciona si estás usando BASH. No conozco la sintaxis DASH (sh) correcta. También se actualizó la respuesta
kvz
1
fwiw, obtengo este error usando bash si hay un espacio entre el <y (. Eso significa que < (falla pero <(las obras, a menos que haya asteriscos en su horario ...
doublesharp
Creo que esta es la forma correcta:cat <(crontab -l |grep -v "${CRON}") <(echo "${CRON}") | crontab -
Stanislav
5

Para una creación / reemplazo agradable y rápido de un crontab con un script BASH, utilicé esta notación:

crontab <<EOF
00 09 * * 1-5 echo hello
EOF
Gibbsoft
fuente
5

Una variante que solo edita crontab si la cadena deseada no se encuentra allí:

CMD="/sbin/modprobe fcpci"
JOB="@reboot $CMD"
TMPC="mycron"
grep "$CMD" -q <(crontab -l) || (crontab -l>"$TMPC"; echo "$JOB">>"$TMPC"; crontab "$TMPC")
Gerald Schade
fuente
3

Si está utilizando Vixie Cron, por ejemplo, en la mayoría de las distribuciones de Linux, puede poner un archivo en /etc/cron.d con el cronjob individual.

Esto solo funciona para root, por supuesto. Si su sistema lo admite, debería ver varios ejemplos allí. (Tenga en cuenta el nombre de usuario incluido en la línea, en la misma sintaxis que el antiguo / etc / crontab)

Es una mala característica triste en cron que no hay forma de manejar esto como un usuario normal, y que muchas implementaciones de cron no tienen forma de manejar esto.

arrojar
fuente
2

Entonces, en Debian, Ubuntu y muchas distribuciones similares basadas en Debian ...

Hay un mecanismo de concatenación de tareas cron que toma un archivo de configuración, los agrupa y los agrega a su servicio cron en ejecución.

Puede colocar un archivo debajo de /etc/cron.d/somefilename donde somefilename es lo que desee.

sudo echo "0,15,30,45 * * * * ntpdate -u time.nist.gov" >> /etc/cron.d/vmclocksync

Desarmemos esto:

sudo: porque necesita privilegios elevados para cambiar las configuraciones de cron en el directorio / etc

echo - un vehículo para crear salida en std out. printf, cat ... también funcionaría

"- usa una comilla doble al comienzo de tu cadena, eres un profesional

0,15,30,45 * * * * - el cronograma estándar de ejecución cron, este se ejecuta cada 15 minutos

ntpdate -u time.nist.gov: el comando real que quiero ejecutar

"- porque mis primeras comillas dobles necesitan un amigo para cerrar la línea que sale

>> - se agrega la redirección doble en lugar de sobrescribir *

/etc/cron.d/vmclocksync: vmclocksync es el nombre de archivo que he elegido, va en /etc/cron.d/


* si utilizamos la redirección>, podemos garantizar que solo tengamos una entrada de tarea. Pero correríamos el riesgo de eliminar cualquier otra regla en un archivo existente. Puedes decidir por ti mismo si la destrucción posible con> es correcta o si los duplicados con >> son para ti. Alternativamente, puede hacer algo complicado o involucrado para verificar si el nombre del archivo existe, si hay algo en él y si está agregando algún tipo de duplicado, pero tengo cosas que hacer y no puedo hacerlo por tu ahora mismo.

BradChesney79
fuente
2

Script Bash para agregar trabajo cron sin el editor interactivo. El siguiente código ayuda a agregar un cronjob usando archivos de Linux.

#!/bin/bash

cron_path=/var/spool/cron/crontabs/root

#cron job to run every 10 min.
echo "*/10 * * * * command to be executed" >> $cron_path

#cron job to run every 1 hour.
echo "0 */1 * * * command to be executed" >> $cron_path
akash
fuente
1
Sé que ha sido muuuucho tiempo, pero esta sigue siendo la única respuesta correcta, ya que todos los más votados eliminan los viejos crons en lugar de simplemente agregar el nuevo.
afe
1
Este no instala un cron. Simplemente lo agrega a un archivo. Tendrá que notificar de alguna manera al proceso cron para instalar la nueva entrada.
Apoorv Parijat
2
echo "0 * * * * docker system prune --force >/dev/null 2>&1" | sudo tee /etc/cron.daily/dockerprune
usuario11547308
fuente
1

Aquí hay una función bash para agregar un comando crontabsin duplicación

function addtocrontab () {
  local frequency=$1
  local command=$2
  local job="$frequency $command"
  cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -
}
addtocrontab "0 0 1 * *" "echo hello"
Klas Mellbourn
fuente
1
CRON="1 2 3 4 5 /root/bin/backup.sh" 
cat < (crontab -l) |grep -v "${CRON}" < (echo "${CRON}")

agregue el parámetro -w al comando exacto grep, sin el parámetro -w agregue el cronjob "testing", porque se elimina el trabajo cron "testing123"

función de script para agregar / eliminar cronjobs. sin entradas duplicadas:

cronjob_editor () {         
# usage: cronjob_editor '<interval>' '<command>' <add|remove>

if [[ -z "$1" ]] ;then printf " no interval specified\n" ;fi
if [[ -z "$2" ]] ;then printf " no command specified\n" ;fi
if [[ -z "$3" ]] ;then printf " no action specified\n" ;fi

if [[ "$3" == add ]] ;then
    # add cronjob, no duplication:
    ( crontab -l | grep -v -F -w "$2" ; echo "$1 $2" ) | crontab -
elif [[ "$3" == remove ]] ;then
    # remove cronjob:
    ( crontab -l | grep -v -F -w "$2" ) | crontab -
fi 
} 
cronjob_editor "$1" "$2" "$3"

probado:

$ ./cronjob_editor.sh '*/10 * * * *' 'echo "this is a test" > export_file' add
$ crontab  -l
$ */10 * * * * echo "this is a test" > export_file
speefak
fuente
Si tiene el mismo comando en el crontab dos veces (ejecutándose en diferentes momentos), la eliminación eliminará ambas líneas.
Michaelkay
1

Mi solución preferida para esto sería esta:

(crontab -l | grep . ; echo -e "0 4 * * * myscript\n") | crontab -

Esto asegurará que está manejando la nueva línea en blanco en la parte inferior correctamente. Para evitar problemas con crontab, generalmente debe finalizar el archivo crontab con una nueva línea en blanco. Y el script anterior se asegura de que primero elimine las líneas en blanco con el "grep". parte, y luego agregue una nueva línea en blanco al final con "\ n" al final de la secuencia de comandos. Esto también evitará que aparezca una línea en blanco encima de su nuevo comando si su archivo crontab existente termina con una línea en blanco.

gsus
fuente
0

No, no hay opción en crontab para modificar los archivos cron.

Debe: tomar el archivo cron actual (crontab -l> newfile), cambiarlo y colocar el nuevo archivo en su lugar (crontab newfile).

Si está familiarizado con perl, puede usar este módulo Config :: Crontab .

LLP, Andrea

andcoz
fuente
0

función de script para agregar cronjobs. verificar entradas duplicadas, expresiones utilizables *> "

cronjob_creator () {         
# usage: cronjob_creator '<interval>' '<command>'

  if [[ -z $1 ]] ;then
    printf " no interval specified\n"
elif [[ -z $2 ]] ;then
    printf " no command specified\n"
else
    CRONIN="/tmp/cti_tmp"
    crontab -l | grep -vw "$1 $2" > "$CRONIN"
    echo "$1 $2" >> $CRONIN
    crontab "$CRONIN"
    rm $CRONIN
fi
}

probado:

$ ./cronjob_creator.sh '*/10 * * * *' 'echo "this is a test" > export_file'
$ crontab  -l
$ */10 * * * * echo "this is a test" > export_file

fuente: mi cerebro;)


fuente
-5

Probablemente pueda cambiar el editor predeterminado a ed y usar un heredoc para editar.

EDITOR=ed
export EDITOR

crontab -e << EOF
> a
> * * * * * Myscript
> * * * * * AnotherScript
> * * * * * MoreScript
> .
> w
> q
> EOF

Tenga en cuenta el líder > en ese código significa que la tecla de retorno / entrada se presiona para crear una nueva línea.

El a medios APPEND para que no se nada de sobreescritura.

El .significa que ya terminaste de editar.

El w significa ESCRIBIR los cambios.

El q significa SALIR o salir de ed.

puedes echarle un vistazo

crontab -l

También puedes eliminar una entrada.

EDITOR=ed
export EDITOR

crontab -e << EOF
> /Myscript/
> d
> .
> w
> q
> EOF

Eso eliminará la entrada crontab con Myscript.

La d significa eliminar el patrón dentro de / / .

No verifique de nuevo

crontab -l

Esta solución funciona dentro de un script también menos la > por supuesto :-)

Jetchisel
fuente