¿Ejecutar un trabajo cron el primer lunes de cada mes?

32

Me gustaría ejecutar un trabajo de cron a las 8.30 el primer lunes de cada mes. La página cron de Wikipedia dice

Aunque normalmente el trabajo se ejecuta cuando los campos determinados de tiempo / fecha todos coinciden con la hora y fecha actuales, hay una excepción: si ambos "día del mes" y "día de la semana" están restringidos (no "*"), a continuación, ya sea el campo "día del mes" (3) o el campo "día de la semana" (5) deben coincidir con el día actual.

(mi énfasis)

¿Eso significa que no puedo hacer el primer lunes del mes, solo puedo hacer el primer (o lo que sea) día del mes? No puedo pensar en una forma de evitarlo.

Max Williams
fuente
slhck, que suena como una buena solución, ¿le importaría ampliarlo en una respuesta con el código completo? entonces lo marcaré como correcto :)
Max Williams

Respuestas:

39

Puede poner la condición en el comando crontab real:

[ "$(date '+%a')" = "Mon" ] && echo "It's Monday"

Ahora, si esta condición es cierta en uno de los primeros siete días de un mes, tiene su primer lunes. Tenga en cuenta que en el crontab, el porcentaje de sintaxis debe ser escapado:

0   12  1-7 *   *   [ "$(date '+\%a')" = "Mon" ] && echo "It's Monday"

Reemplace el echocomando con el comando real que desea ejecutar. También encontré un enfoque similar .

slhck
fuente
De hecho, slhck, hablé demasiado pronto, esto no funciona en mi crontab: parece que hay un problema con la prueba de fecha por alguna razón. Esto funciona en la línea de comando al [ "$(date '+%a')" = "Mon" ] && echo "It's Monday"igual que [ $(date '+%a') = "Mon" ] && echo "It's Monday" Pero, en el crontab parece estar fallando en esta prueba. No puedo obtener ningún comentario útil de cron tampoco: estoy tratando [ "$(date '+%a')" = "Tue" ] >> /home/deploy/cron.log 2>&1de capturar cualquier salida de error en un registro, pero eso tampoco funciona: /
Max Williams
Hm. ¿Puedes verificar si la datesalida es correcta? Por ejemplo, simplemente deje cronque se ejecute un comando que muestre esto en un archivo: date '+%a' > ~/datetest 2>&1- luego verifique si eso resultó en la cadena correcta para comparar.
slhck
1
He encontrado el problema - el porcentaje en +%anecesario escapar cuando estaba en el crontab, es decir, la línea tenía que ser la siguiente: [ "$(date '+\%a')" = "Mon" ] && echo "It's Monday". Si pudiera actualizar su respuesta con eso, sería útil para futuros lectores :) Gracias de nuevo - max
Max Williams
Oh, ahora veo por qué. Me alegro de que funcione ahora, ¡gracias por probarlo!
slhck
15

Tengo una computadora con configuración regional en español, por lo que este enfoque no funciona para mí porque mon cambia a lun

Otros idiomas también fallarían, así que hice una ligera variación en la respuesta aceptada que elimina la barrera del idioma:

 0 9 1-7 * *   [ "$(date '+\%u')" = "1" ] && echo "¡Es lunes!"
cumanacr
fuente
+1 ¡Muy bien, señor!
JakeGould
1
Gracias ¡Pura vida! ; D
cumanacr
Esta debería ser la respuesta aceptada. Tengo una configuración holandesa que también usa diferentes nombres para los días de semana. Y usar números también se siente más limpio que comparar cadenas para determinar el día de la semana.
0ne_Up
7

Me resulta más fácil cuando no hay necesidad de manejar los números de día.

Ejecutar primer lunes de mes:

0 2 * * 1 [ `date '+\%m'` == `date '+\%m' -d "1 week ago"` ] || /path/to/command

es decir, si el mes de hace 1 semana no es el mismo que el mes actual, estamos en el primer día 1 (= lunes) del mes.

Del mismo modo, para el tercer viernes

0 2 * * 6 [ `date '+\%m'` == `date '+\%m' -d "3 weeks ago"` ] || /path/to/command

es decir, si el mes hace 3 semanas es diferente al mes actual, entonces estamos en el tercer día 6 (= viernes) del mes

joel
fuente
El día 6 de la semana es sábado no viernes.
Robert
4

He programado un trabajo para que se ejecute el cuarto lunes de cada mes a las 4:00 p.m. de la siguiente manera:

0 16 22-28 * Mon [ "$(date '+\%a')" == "Mon" ] && touch /home/me/FourthMonOfMonth.txt
Abhijit Mapgaonkar
fuente
1

Por lo que sé, NO es posible usar solo crontab, sin embargo, se puede usar una función de contenedor para elegir el día correcto de una entrada de contacto de los "primeros siete días del mes"; mira esto desde la entrada.

El script de envoltura sería

#! /usr/bin/ksh
day=$(date +%d)
if ((day <= 7)) ; then
   exec somecommand
fi
exit 1

y necesitaría ejecutarlo (asumiendo que se llama wrapper.sh y está disponible globalmente) usando la entrada crontab

0 0 * * 1 wrapper.sh
elemakil
fuente
gracias elemaki. Pensé en una solución similar usando un código adicional dentro de la tarea que se ejecuta, haciendo que pruebe si es el primer lunes del mes dentro del script y luego llamándolo todos los lunes en crontab. Es un script de ruby, por lo que es fácil probar el día de la semana. Pero esperaba que hubiera una única manera de crontab.
Max Williams
1

En Solaris 10 tuve que formatear la condición de la siguiente manera:

[ `date +\%a` = "Sat" ] && echo "It's Saturday"
Será
fuente
1

Puede intentar ejecutar cronjob durante los primeros siete días del mes y dejar que se ejecute solo el lunes.

30 8 * * 1 [`date +\%d` -le 07] && <job>

Arriba debería funcionar para usted.

simer
fuente
+1 más éxito golpeó la ración luego de correr durante la primera semana y comprobar para el lunes. :-)
xmedeko
1

Recomiendo usar

"$(/bin/date '+%\w')" = "1"

en lugar de

"$(date '+\%a')" = "Mon"

para evitar problemas locales.

Libertad de Manus
fuente
0

Hice una solución general para este tipo de problemas, funciona para el primer, segundo, tercer ..... último día de la semana del mes.

Puedes usarlo así:

30 06 * * Mon run-if-today 1 "Mon" && echo "First Monday"
30 06 * * Thu run-if-today 3 "Thu" && echo "Third Thursday"
30 06 * * Sun run-if-today L "Sun" && echo "Last Sunday"

La secuencia de comandos run-if-today verifica tanto el día de la semana como el intervalo de fechas deseado de la semana, si ambos coinciden, devuelve 0, de lo contrario 1.

Consulta el código aquí. https://github.com/xr09/cron-last-sunday

MGP
fuente
0

Creo que esto resuelve el problema con más elegancia:

30 8 1-7 * 1 /run/your/job.sh
symcbean
fuente
1
Doh! : "Si ambos campos están restringidos (es decir, no *), el comando se ejecutará cuando cualquiera de los campos coincida con la hora actual".
symcbean
También en febrero (el que termina el 28) no se ejecutará cada 4 años.
igraczech
"cualquiera" significa cualquiera de ellos, no "ambos". Esto se ejecutará todos los días durante los primeros 7 días del mes.
menos el
Esta fila ejecutaría un comando del primero al séptimo de cada mes, así como también todos los lunes
Tomasz Jakub Rup
0

Como interpreto mis declaraciones cron usando php y js, no puedo usar bash. Finalmente encontré que es de hecho posible con sólo cron:

0 30 8 * 1/1 MON#1

Espero que esto ayude a alguien más. De todos modos, les deseo a todos un hermoso día. :-)

kramer65
fuente
Esto no es cron, es posiblemente cuarzo
sivann
-1
0 9 1-7 * 1 * 

Esto funcionará todos los lunes de cada mes.

SIBHI S
fuente
Se ha aceptado una respuesta, ¿es su respuesta mejor, diferente o útil en una versión más nueva, etc.
Mic84