¿Ejecutar comando una vez transcurrido un cierto período de tiempo?

24

Si estoy ejecutando un proceso largo, ¿hay alguna forma de ejecutar algunos comandos basados ​​en el tiempo?

Por ejemplo, estoy ejecutando un proceso realmente largo que dura aproximadamente 10 minutos.

Después de 5 minutos, me gustaría ejecutar un comando por separado. Por ejemplo, el comando separado podría ser:echo 5 minutes complete

(Nota: no quiero avanzar hacia la finalización del comando, sino simplemente comandos ejecutados después de intervalos especificados).

¿Es posible?

Aniket Bhattacharyea
fuente
1
La mayoría de las veces, no sabes de antemano cuánto tiempo llevará un proceso.
choroba
¿Qué quiere decir "comandos basados ​​en el tiempo"? ¿Quieres crear una barra de progreso? Según la formulación actual de su pregunta, puede poner el comando de ejecución larga en segundo plano y luego mostrar el reloj del sistema. Por favor aclarar
Comodín
@Wildcard Aclaré en la pregunta. No es una barra de progreso. Ejecutará comandos después de algunos intervalos
Aniket Bhattacharyea
1
"5 minutos completos" es algo extraño para hacer eco. ¿No han pasado "5 minutos"? No "El tiempo es _____"? ¿Desea asegurarse de que haya transcurrido un intervalo de tiempo especificado desde el momento en que se inició su comando de ejecución prolongada, antes de ejecutar otro comando arbitrario? Si es así, ¿por qué no simplemente correr longcommand & sleep 300 && command-to-do-after-five-minutes? (En realidad, eso es probablemente lo que está buscando). Tenga en cuenta que su aclaración no fue suficiente, ya que obtuvo dos implementaciones de barra de progreso de reloj desde el principio.
Comodín

Respuestas:

29

Solo corre:

long-command & sleep 300; do-this-after-five-minutes

El do-this-after-five-minutesse ejecutará después de cinco minutos. El long-commandse ejecutará en segundo plano.

Comodín
fuente
10
Usualmente uso sleep 5m && foobar, así que si cambio de opinión y ^ C sleep, el siguiente comando no se ejecuta.
Peter Cordes
@PeterCordes, cuando lo probé con, por ejemplo , sleep 3; lsy ^C, el segundo comando no se ejecuta de todos modos. ¿No estoy seguro de por qué y tal vez funciona de manera diferente en un shell no interactivo?
Comodín
1
@PeterCordes No del todo, a menos que difiera por shell. Cuando sleep 5m && echoestá durmiendo, cuando suspende, solo se suspende el sleepcomando. El resto de la línea de comando se ejecuta, pero desde que sleepse suspendió, no salió con éxito y &&se omite la parte posterior . Intenta suspender sleep 5 || echo helloy helloaparece directamente después de presionar ^Z.
hvd
1
@hvd: Sí, tienes razón, y estoy equivocado de nuevo>. <, usando bash4. Aparentemente ha pasado demasiado tiempo desde que decidí que && era el camino a seguir como gueto at(1), para cosas como sleep 30m && mplayer something.mp3recordatorio de alarma o para sleep 90m && fgreanudar un comando intensivo en disco más tarde. Entonces, en realidad, sleep 5m && echo helloes bueno porque se ^Zsuspende sleepsin ejecutar el siguiente comando. Si desea poder suspender / reanudar todo el comando compuesto, incluso antes de que salga el sueño, use ( sleep 2 && echo hello ).
Peter Cordes
@hvd: El &&modismo le permite estar absolutamente seguro de que no cancela el proceso justo después de que se ejecute el sueño (porque no puede ^Zejecutar el comando, en lugar de arriesgarse a ^C). Esto es útil en la sleep && fgo sleep && bgel uso de los casos, cuando el ser reanudó comando es parte del camino a través de algo lento.
Peter Cordes
5

Podrías usar este script:

#!/bin/bash

TEMPFILE="$(mktemp)"
STARTTIME="$(date +%s)"
(./longprocess; rm -f "$TEMPFILE") &
while [ -f "$TEMPFILE" ]; do
    sleep 1s
    NOW="$(date +%s)"
    if (( (NOW-STARTTIME) % 300 == 0 )); then
        echo "$(( (NOW-STARTTIME)/60 )) minute(s) elapsed"
    fi
done
echo "Done!!!"

Ejecuta su longprocessen sub-shellay luego monitorea la existencia del archivo 'lock' previamente creado.

Sarga
fuente
2
Compruebe man bashpara SECONDS. Se puede establecer SECONDS=0en el arranque de la escritura y sólo comprobar si hay mayor o igual a 300 o el conjunto SECONDS=$((date +%s))y olvidarse de usar datede nuevo en el script ...
@yeti, gracias por la pista, no lo sabía.
Serge
@yeti, si quieres confiar en el tiempo después de sleep 1sestar siempre exactamente un segundo más tarde que antes sleep 1s... entonces has sido víctima de falsedades que los programadores creen sobre el tiempo . (Aunque en este caso, también podría mostrar una barra de progreso de marca hash o algo así).
Comodín
@Wildcard ... ¡No lo mencioné sleepen absoluto!
@Yeti, tienes razón. Gracias por el consejo sobre SECONDS! :)
Comodín
4

Hay una línea para esto:

( ( sleep $TIMEOUT ; echo "5 minutes complete") & $COMMAND )

En su caso, TIMEOUT = 5m y COMMAND es el comando largo.

También vea mi respuesta a esta publicación Tiempo de espera con 'reinicio de red de servicio'

taza de cafe
fuente
Lanzar una subshell en primer plano y luego ejecutar el comando parece innecesariamente complicado. Quitaría los paréntesis externos y el ejecutivo.
Glenn Jackman
1
@glennjackman De esta manera, se puede eliminar todo el procedimiento enviando CTRL + C (por ejemplo) al subconcha principal (más externo).
coffeMug
1
Pero usando exec, ya no tienes una subshell, solo tienes el comando. El padre del comando es el shell que ejecuta el script como si no hubiera usado un subshell en absoluto.
Glenn Jackman
3
#! /bin/bash

( sleep 4 ) & # <-- The long running process.

seconds=1
while jobs %1 &>/dev/null ; do
    echo $((seconds++)) seconds complete
    sleep 1    
done
echo Done.

jobs %1 falla una vez que el trabajo% 1 se ha detenido.

Tenga en cuenta que para tiempos más largos, $ segundos pueden no estar sincronizados con el tiempo real. Es mejor almacenar la hora de inicio y calcular la diferencia con la hora real.

choroba
fuente