Ejecutar comando cada X segundos

10

Deseo ejecutar un comando cada 10 segundos y ejecutarlo en segundo plano ( watch¿ eliminando así ?). Todas las respuestas muestran algo como lo siguiente, pero esto se ejecutará cada 11 a 14 segundos. ¿Cómo se puede lograr esto?

while true; do
    # perform command that takes between 1 and 4 seconds
    sleep 10
done
usuario1032531
fuente
quizás con señales en tiempo real. y manejo adecuado de los segundos bisiestos. buena suerte.
mikeserv
@mikeserv Entonces, ¿no te molestas en intentarlo? No me importa la precisión de milisegundos, solo digamos medio segundo.
user1032531
¿Qué estás tratando de lograr? Encuentro que una tarea que tiene que ejecutarse con ese tipo de frecuencia suele ser una solución para otro problema.
Sobrique
@Sobrique Exactamente. Estoy haciendo una prueba de concepto de un registrador de datos de sondeo. En realidad, se programará en algún otro idioma, pero esto funciona por ahora.
user1032531

Respuestas:

16

Qué tal si:

( # In a subshell, for isolation, protecting $!
  while true; do
    perform-command & # in the background
    sleep 10 ;
    ### If you want to wait for a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line:
    # wait $! ;
    ### If you prefer to kill a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line instead:
    # kill $! ;
    ### (If you prefer to ignore it, uncomment neither.)
  done
)

ETA: con todos esos comentarios, alternativas y la subshell para una protección adicional, parece mucho más complicado de lo que comenzó. Entonces, a modo de comparación, esto es lo que parecía antes de comenzar a preocuparme waito killcon su $!necesidad de aislamiento:

while true; do perform-command & sleep 10 ; done

El resto es realmente solo para cuando lo necesites.

El sidhekin
fuente
¿Puedes explicar el razonamiento detrás de tu volcado de código?
Ismael Miguel
2
Además, para citar las que Shell sus obras de código para (como la respuesta de mikeserv) para que la gente no se confunden cuando un shell diferentes comporta de forma diferente :)
ceniza
@IsmaelMiguel Supuse que los comentarios explicarían el razonamiento. No estoy seguro de lo que no está claro.
El Sidhekin
1
El manual de bash dice $!: "Se expande al ID de proceso del trabajo colocado más recientemente en el fondo", y sleepno se coloca en el fondo, por lo que no, no lo hará. :)
El Sidhekin
1
Guau. mal en ambos aspectos. ¿cuando sucedió eso?
mikeserv
9

Usted puede hacer algo como lo siguiente en bash, zsho ksh:

SECONDS=0
while   command
do      sleep "$((10-(SECONDS%10)))"
done

Esto es lo bashque dice el manual sobre $SECONDS:

$SECONDS

  • Cada vez que se hace referencia a este parámetro, el número de segundos desde que se devuelve la invocación de shell. Si se asigna un valor $SECONDS, el valor devuelto en referencias posteriores es el número de segundos desde la asignación más el valor asignado. Si $SECONDSes así unset, pierde sus propiedades especiales, incluso si se restablece posteriormente.

Aquí hay un ejemplo de trabajo:

(   SECONDS=0
    while   sleep   "$((RANDOM%10))"
    do      sleep   "$((10-(SECONDS%10)))"
            echo    "$SECONDS"
    done
)

10
20
30
40
50
60
70
80
90
100
mikeserv
fuente
2
Para evitar reiniciar SECONDShacer sleep "$((10-(($SECONDS-$start_time)%10)))". Tendrás que hacer start_time=$SECONDSantes del bucle.
ctrl-alt-delor
@richard: ¿por qué evitarlo?
mikeserv
porque un día lo tendrás en un script desde el que llamas dentro de ese bucle. Y pasará todo el día preguntándose por qué no funciona correctamente. En resumen, no se anida, si restablece SECONDS. Generar un sub-shell como en su última edición, también debería evitar este problema.
ctrl-alt-delor
1
@richard: dado que la pregunta era sobre un while truebucle, no pensé que se esperaba que ningún estado shell sobreviviera. Ajustar un bucle como ese en su propio contexto suele ser la mejor práctica, de todos modos. Sin embargo, en una situación así, me preocuparía más hacerlo por trapel bien que por $SECONDSel bien.
mikeserv
Gracias Mike, estaba pensando en hacer algo similar (pero aún no sabía los detalles). Pero la solución de Sidhekin parece hacer lo mismo, ¿no? No estoy calificado para juzgar la mejor respuesta, pero me siento obligado a elegir algo.
user1032531
3

BASH solamente: también puede calcular el tiempo que dedica su comando y restar de 10:

TIMEFORMAT=$'%0R'
while true; do
    T=$({ time command; } 2>&1)
    sleep $(( 10-T ))

Del hombre BASH:

TIMEFORMAT El valor de este parámetro se usa como una cadena de formato que especifica cómo se debe mostrar la información de tiempo para las tuberías con el prefijo de la palabra reservada en el tiempo. El carácter% introduce una secuencia de escape que se expande a un valor de tiempo u otra información. Las secuencias de escape y sus significados son los siguientes; las llaves denotan porciones opcionales.
%% Un literal%.
% [p] [l] R El tiempo transcurrido en segundos.
% [p] [l] U El número de segundos de CPU gastados en modo usuario.
% [p] [l] S El número de segundos de CPU gastados en modo sistema.
% P El porcentaje de CPU, calculado como (% U +% S) /% R.

La p opcional es un dígito que especifica la precisión, el número de dígitos fraccionarios después de un punto decimal. Un valor de 0 hace que no se genere ningún punto decimal o fracción.

Dani_l
fuente