Problema con $ RANDOM en crontab

9

Tengo un problema extraño con $ RANDOM en cron. Deseo ejecutar un comando un número aleatorio de minutos después de que se active el cronjob.

Este ejemplo funciona directamente en el terminal y retrasa el comando hasta 30 segundos (reemplace el comando con lo que quiera, en realidad es un eco para / dev / ttyUSB0):

sleep `expr $RANDOM \% 30` ; command

Si se coloca la misma línea en crontab, el comando siempre se dispara inmediatamente sin demora:

* * * * * sleep `expr $RANDOM \% 30` ; command

Si uso una expresión sin $ RANDOM, funciona bien, esto demora 15 segundos:

* * * * * sleep `expr 10 + 5` ; command

En otras palabras, parece que $ RANDOM no funciona en un cron.

Pero no es simplemente porque $ RANDOM mismo se evalúa a cero, porque entonces esto debería dar un retraso de 10:

* * * * * sleep `expr $RANDOM \% 30 + 10` ; command

También he intentado con && instread of; Pero eso no ayuda. De hecho, entonces el comando no se dispara en absoluto.

Por supuesto, podría colocar el retraso en un script que luego se llama desde crontab, pero eso no explica mi problema y no me hace aprender :-)

Es Debian Lenny si eso hace alguna diferencia.

marlar
fuente

Respuestas:

17

cronusa el /bin/shshell para ejecutar tareas. En algunas distribuciones, este es un enlace simbólico a dash. Ninguno de ellos admite la $RANDOMvariable, que es una bashextensión específica.

  • Con vixie-cron, puede poner una línea SHELL=/bin/bashen la parte superior de su crontab.

  • De lo contrario, tendrá que conformarse con bash -c 'echo $RANDOM'o perl -e 'print int(rand(65535))'.

    (En el ejemplo anterior, 65535 es el número máximo a devolver. También puede aplicar otras matemáticas dentro del script).

  • En un sistema configurado correctamente, se lo habría informado por cronsí mismo: siempre envía la salida del trabajo, incluidos los mensajes de error, por correo electrónico. Instale un MTA ligero.


Además, en bash, $(( ))se prefiere sobre `expr`.

usuario1686
fuente
Lo último que comprobé /bin/shfue que no era un shell real, simplemente un enlace simbólico al shell preferido del sysadmin (típicamente bash o dash) en Debian.
Hola71
1
@ Hello71: que es lo que dije en la publicación. Sin embargo, es habitual que el software del sistema invoque /bin/sh(y espere que sea compatible con Bourne Shell). Un ejemplo es la system()función en glibc. Por /bin/shlo tanto, generalmente apunta al shell más rápido compatible con Bourne; y el administrador del sistema debe establecer su preferencia en la línea apropiada de / etc / passwd, no imponer esa preferencia en todo el sistema
user1686
@ Hello71: ... bueno, sobre todo lo que dije en la publicación. (Sé que la mayoría de las otras distribuciones enlazan sha bash, pero no parecía relevante.)
user1686
Tienes razón, /bin/shapunta al guión. Hasta ahora, nunca escuché sobre dash. Lo busqué y es una variante ligera de bash. Además, no sabía que cron se ejecutaba en un entorno "lisiado", pero explica varios otros problemas que he tenido en el pasado. Por cierto, comencé a usarlo, $(())pero como no funcionó, probé todo tipo de variaciones y terminé con lo exprque, por supuesto, tampoco funcionó. Pero ahí es donde terminé :-) ¿Es posible ejecutar un shell bash normal sin las limitaciones de uso bash -c 'xxxx'? Por cierto, ¿no es posible poner saltos de línea en los comentarios?
marlar
@marlar: 1) dashes un shell. No es más ni menos normal que bash. Tampoco es una variante. 2) Vea los puntos 1 y 2 en la respuesta.
user1686
2

cronnormalmente se ejecuta con un entorno menos "completo", lo que significa que simplemente no tiene muchas de las mismas variables de entorno disponibles. Aparentemente $RANDOMes uno de esos, y de hecho, su sleepcomando simplemente está fallando con un error debido a la variable indefinida, por lo que su comando no se ejecutó en absoluto cuando cambió a en &&lugar de ;. (Bueno, en realidad, $RANDOMes una función Bash, pero cronno se ejecuta en un entorno Bash completo, que evidentemente carece de esta función).

Para llevar a cabo esta tarea, necesitará usar un script Bash separado, como dijo. Alternativamente, es posible que pueda encontrar una manera de usar cat /dev/urandomdirectamente en el croncomando, pero probablemente sería más fácil mover lo que tiene actualmente a un script Bash separado.

Kromey
fuente
1
No es bonito, pero encontré esta solución que es análoga a su sugerencia: sleep $ (expr od -An -N1 -i /dev/urandom\% 30); comando
marlar
1
$RANDOMno es parte de un entorno "completo". No tiene nada que ver con las variables de entorno establecidas al inicio del proceso. Es una variable especial creada "sobre la marcha" en bash. Su nuevo valor siempre se genera cada vez que se lee la variable. --- cronpor defecto se usa /bin/shen sistemas donde /bin/shno está vinculado bash $RANDOMno funcionará de manera predeterminada.
pabouk