Shell: ¿es posible retrasar un comando sin usar 'sleep'?

21

¿Hay sustitutos, alternativas o trucos bash para retrasar comandos sin usar sleep? Por ejemplo, realizar el siguiente comando sin usar el modo de suspensión:

$ sleep 10 && echo "This is a test"
user321697
fuente
42
¿Qué tiene de malo sleep?
muru
55
No hay otra razón real que la curiosidad. Pensé que sería interesante aprender algunas soluciones alternativas. Creo que atpodría ser uno, pero no pude encontrar ningún ejemplo de uso.
usuario321697
1
@ user321697 "at" es para programar trabajos individuales. son ejecutados por el servicio atd, por lo que no pausarán su script de shell. un caso de uso para at sería hacer que haga algo a una hora específica (asíncrona) y crear un archivo marcador cuando esté terminado, mientras su script espera que ese archivo aparezca en un ciclo while. puede lograr un efecto similar al programar un trabajo para enviar su script a SIGCONT y luego congelar su script enviándose un SIGSTOP.
Grega Bremec
1
Vine aquí esperando que todos sugieran un spinlock. Estoy gratamente sorprendido por todas las respuestas.
Daan van Hoek
3
Re: "La curiosidad" - en unix.stackexchange.com/help/dont-ask , tenga en cuenta el requisito de que "Sólo se debe hacer preguntas prácticas que puedan responderse sobre la base de los problemas reales que enfrentan. " - que esto ha sido bien recibido a pesar de controlar esa directriz, es una excepción bastante rara.
Charles Duffy

Respuestas:

17

Tienes alternativas a sleep: Son aty cron. Contrariamente a sleepesto, necesita proporcionar el tiempo en el que necesita que se ejecuten.

  • Asegúrese de que el atdservicio se esté ejecutando ejecutándolo service atd status.
    Ahora digamos que la fecha es 11:17 am UTC; si necesita ejecutar un comando a las 11:25 GMT, la sintaxis es: echo "This is a test" | at 11:25.
    Ahora tenga en cuenta que, atdde forma predeterminada, no se registrará la finalización de los trabajos. Para más información consulte este enlace . Es mejor que su aplicación tenga su propio registro.

  • Puede programar trabajos en cron, para más información: man cronpara ver sus opciones o crontab -epara agregar nuevos trabajos. /var/log/cronse puede verificar la información sobre la ejecución de trabajos.

FYI sleep system call suspende la ejecución actual y lo programa con el argumento que se le pasó.

EDITAR:

Como @Gaius mencionó, también puede agregar minutos de tiempo al comando, pero atdigamos que es la hora 12:30:30y ahora ejecutó el programador now +1 minutes. A pesar de que se especificó 1 minuto, que se traduce en 60 segundos, atrealmente no espera hasta 12:31:30ejecutar el trabajo, sino que ejecuta el trabajo en 12:31:00. Las unidades de tiempo pueden ser minutes, hours, days, or weeks. Para más consultaman at

p.ej: echo "ls" | at now +1 minutes

ss_iwe
fuente
77
Esto no es cierto, puede programar un trabajo en, digamos ahora +1 minuto, para que se ejecute en unos minutos
Gaius
29

Con bashbuiltins, puedes hacer:

coproc read -t 10 && wait "$!" || true

Dormir durante 10 segundos sin usar sleep. El coprocobjetivo es hacer que readel stdin sea una tubería de la que nunca saldrá nada. || truees porque waitel estado de salida reflejará una entrega SIGALRM que provocaría que el shell salga si errexitse establece la opción.

En otras conchas:

mkshy ksh93tienen sleepincorporado, no tiene sentido usar nada más allí (aunque ambos también son compatibles read -t).

zshtambién es compatible read -t, pero también tiene un envoltorio incorporado select(), por lo que también puede usar:

zmodload zsh/zselect
zselect -t 1000 # centiseconds

Si lo que desea es programar cosas para que se ejecuten desde una sesión de shell interactiva, consulte también el zsh/schedmódulo enzsh .

Stéphane Chazelas
fuente
¿Lo considerarías read -t 10 < /dev/zero || true?
Jeff Schaller
55
@JeffSchaller Lo evitaría, ya que es un ciclo muy ocupado.
Stéphane Chazelas
@ StéphaneChazelas No esperaría que fuera un bucle ocupado: esperaría que cualquier shell readse implementara usando select (2) o algo similar (lo que implica que leer con tiempo de espera sería una buena respuesta a esta pregunta). Estoy expresando sorpresa en lugar de contradecirlo, pero ¿puede señalar una discusión adicional sobre esto?
Norman Gray
55
@ NormanGray, /dev/zeroes un archivo que contiene una cantidad infinita de datos (bytes NUL). Entonces readleerá todo lo que pueda durante esos 10 segundos. Afortunadamente, en el caso de bashque no sea compatible con el almacenamiento de bytes NUL en sus variables, eso no usará ninguna memoria, pero aún así acaparará los recursos de la CPU.
Stéphane Chazelas
1
@NormanGray, si se ejecuta desde una terminal, /dev/stdoutsería el dispositivo tty, por lo que tendría efectos secundarios (como detener el script si se ejecuta en segundo plano) y volvería si el usuario presiona Enter, por ejemplo. read -t 10 /dev/stdout | :funcionaría en Linux, pero solo en Linux, mientras que coprocdebería funcionar independientemente del sistema operativo.
Stéphane Chazelas
7

Algunas otras ideas

top -d10 -n2 >/dev/null

vmstat 10 2 >/dev/null

sar 10 1 >/dev/null

timeout 10s tail -f /dev/null
Steve
fuente
1
Usted "robó" mi idea de límite de tiempo / tiempo de espera ... +1
Rui F Ribeiro
1
Ohhhh, gracias, estaba en una situación sin dormir, ¡lo mejor es increíble!
Fire-Dragon-DoL
6

Dado que hay respuestas que sugieren utilizar la -t delayopción no estándar de read, aquí hay una manera de hacer una lectura expirada en un shell estándar:

{ ss=`stty -g`; stty -icanon min 0 time 20; read foo; stty "$ss"; }

El argumento de stty timeestá en décimas de segundo.

Mosvy
fuente
5

Usando la variable incorporada bash $SECONDSy un loop ocupado:

for((target=$((SECONDS + 10)); SECONDS < target; true)); do :; done
Jeff Schaller
fuente
2
Sin embargo, eso se pausaría durante un período de tiempo entre 9 y 10 segundos (debido a un errorbash , zshy mkshtuvo problemas similares, pero se han solucionado desde entonces)
Stéphane Chazelas
77
Una buena forma de hacer calor.
ctrl-alt-delor
66
¡No será la primera vez que me acusen de estar lleno de aire caliente! :)
Jeff Schaller
4

El truco más antiguo del libro:

read && echo "This is a test"

¡Solo golpea Entery continuará!

Fabby
fuente
Esto no funcionará si el proceso necesita ejecutarse sin interacción o en segundo plano, ¿verdad?
ss_iwe
Correcto: Pero ese no era uno de los requisitos del OP según la pregunta original, por lo que sigue siendo una respuesta válida ... ;-)> :-)
Fabby
1
OP específicamente da un ejemplo (con sleep) y solicita una alternativa equivalente sin. Así readque no analiza, lo siento. ;)
AnoE
La respuesta de @AnoE Stéphane es, por supuesto, la mejor, la mía es la más antigua --- press «enter» to continue --- ;-)
Fabby
4

En los días de los microordenadores que ejecutaban BASIC, los retrasos generalmente se lograban con un bucle vacío:

FOR I = 1 TO 10000:NEXT

El mismo principio podría usarse para insertar un retraso en un script de shell:

COUNTER=0; while [ $COUNTER -lt 10000 ]; do :; let COUNTER=COUNTER+1; done

Por supuesto, el problema con este enfoque es que la duración del retraso variará de una máquina a otra de acuerdo con la velocidad de su procesador (o incluso en la misma máquina bajo diferentes cargas). A diferencia sleep, probablemente también maximizará su CPU (o uno de sus núcleos).

Psiconauta
fuente
2
Una buena forma de hacer calor.
ctrl-alt-delor
2
Los loops de retardo son una idea terrible para cualquier cosa, excepto para dormir muy poco (un par de nanosegundos o ciclos de reloj en un controlador de dispositivo) en cualquier CPU moderna que pueda ejecutar un sistema operativo tipo Unix. es decir, una suspensión tan corta que no puede hacer que la CPU haga nada mientras espera, como programar otro proceso o entrar en un estado de suspensión de baja potencia antes de despertarse con una interrupción del temporizador. La frecuencia dinámica de la CPU hace que sea imposible incluso calibrar un bucle de retardo para conteos por segundo, excepto como un retraso mínimo que potencialmente duerme mucho más a velocidades de reloj bajas antes de acelerar.
Peter Cordes
Las computadoras antiguas tenían un consumo de energía que dependía mucho menos de la carga de trabajo. Las CPU modernas necesitan apagar dinámicamente diferentes partes del chip tanto como sea posible para no derretirse (por ejemplo, apagar partes de las unidades de ejecución FPU o SIMD mientras solo se está ejecutando el código entero, o al menos enviar la señal del reloj a partes del chip eso no necesita estar cambiando). Y entrar en un estado de reposo de baja potencia cuando está inactivo (en lugar de girar en un bucle infinito esperando interrupciones del temporizador) también es más reciente que las computadoras antiguas que mencionas.
Peter Cordes
Para obtener más información sobre el historial de la CPU, consulte Microprocesadores modernos ¡Una guía de 90 minutos! - lighterra.com/papers/modernmicroprocessors .
Peter Cordes
3

No hay una función integrada, que hace lo mismo que sleep(a menos que sleepesté integrada). Sin embargo, hay otros comandos que esperarán.

Algunos incluyen.

  • aty cron: se utiliza para programar tareas en un momento específico.

  • inotifywait: se usa para esperar un archivo, o archivos para ser modificados / eliminados / agregados / etc.

ctrl-alt-delor
fuente
Gracias por esto. ¿Podría proporcionar un ejemplo para realizar una tarea programada (dentro de 10 segundos) at?
user321697
1
una edición y un voto a favor! ;-)
Fabby
cronalmacenar tareas en crontab, ¿verdad? ¿Dónde atalmacena los datos programados?
user321697
@ user321697 ya respondió aquí
Fabby
Perdón por revertir su edición a la P: cambió el propósito principal de la pregunta de OP que invalidaría la respuesta más simple de todas ... ¯ \ _ (ツ) _ / ¯
Fabby
3

Un clásico de la tierra de Windows y lotes:

ping -c 11 localhost >/dev/null && echo "This is a test"
Joker_vD
fuente
La configuración incorrecta del cortafuegos o del sistema de nombres podría introducir un retraso adicional significativo.
espectros
1
127.0.0.1 ... @spectras
Año
1
Afortunadamente, ya no es necesario, ya que Windows ahora admite el sueño de forma nativa.
Baldrickk
1
@AnoE> resuelve la parte del sistema de nombres, no la parte del firewall. Aunque no es común, se puede configurar para colocar silenciosamente pings en la interfaz local. Eso hará que el ping espere mucho más.
espectros
+1 para los recuerdos "aficionados"
AC
0

Si desea esperar interactivamente una nueva línea en un archivo, entonces

tail -f
.

¿Esperando un cambio en un sistema de archivos? Entonces use eg

inotify / inoticoming
.

Y hay otras opciones, dependiendo de lo que quiera decir con "esperar".

Edheldil
fuente