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:
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
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:
@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 102>/dev/null
sar 101>/dev/null
timeout 10s tail -f /dev/null
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.
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! :)
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).
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.
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"
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".
sleep
?at
podría ser uno, pero no pude encontrar ningún ejemplo de uso.Respuestas:
Tienes alternativas a
sleep
: Sonat
ycron
. Contrariamente asleep
esto, necesita proporcionar el tiempo en el que necesita que se ejecuten.Asegúrese de que el
atd
servicio se esté ejecutando ejecutándoloservice 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,
atd
de 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 cron
para ver sus opciones ocrontab -e
para agregar nuevos trabajos./var/log/cron
se 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
at
digamos que es la hora12:30:30
y ahora ejecutó el programadornow +1 minutes
. A pesar de que se especificó 1 minuto, que se traduce en 60 segundos,at
realmente no espera hasta12:31:30
ejecutar el trabajo, sino que ejecuta el trabajo en12:31:00
. Las unidades de tiempo pueden serminutes, hours, days, or weeks
. Para más consultaman at
p.ej:
echo "ls" | at now +1 minutes
fuente
Con
bash
builtins, puedes hacer:Dormir durante 10 segundos sin usar
sleep
. Elcoproc
objetivo es hacer queread
el stdin sea una tubería de la que nunca saldrá nada.|| true
es porquewait
el estado de salida reflejará una entrega SIGALRM que provocaría que el shell salga sierrexit
se establece la opción.En otras conchas:
mksh
yksh93
tienensleep
incorporado, no tiene sentido usar nada más allí (aunque ambos también son compatiblesread -t
).zsh
también es compatibleread -t
, pero también tiene un envoltorio incorporadoselect()
, por lo que también puede usar:Si lo que desea es programar cosas para que se ejecuten desde una sesión de shell interactiva, consulte también el
zsh/sched
módulo enzsh
.fuente
read -t 10 < /dev/zero || true
?read
se 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?/dev/zero
es un archivo que contiene una cantidad infinita de datos (bytes NUL). Entoncesread
leerá todo lo que pueda durante esos 10 segundos. Afortunadamente, en el caso debash
que 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./dev/stdout
serí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 quecoproc
debería funcionar independientemente del sistema operativo.Algunas otras ideas
fuente
Dado que hay respuestas que sugieren utilizar la
-t delay
opción no estándar deread
, aquí hay una manera de hacer una lectura expirada en un shell estándar:El argumento de
stty time
está en décimas de segundo.fuente
Usando la variable incorporada bash
$SECONDS
y un loop ocupado:fuente
bash
,zsh
ymksh
tuvo problemas similares, pero se han solucionado desde entonces)El truco más antiguo del libro:
¡Solo golpea Entery continuará!
fuente
sleep
) y solicita una alternativa equivalente sin. Asíread
que no analiza, lo siento. ;)--- press «enter» to continue ---
;-)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).fuente
No hay una función integrada, que hace lo mismo que
sleep
(a menos quesleep
esté integrada). Sin embargo, hay otros comandos que esperarán.Algunos incluyen.
at
ycron
: 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.fuente
at
?cron
almacenar tareas encrontab
, ¿verdad? ¿Dóndeat
almacena los datos programados?Un clásico de la tierra de Windows y lotes:
fuente
Si desea esperar interactivamente una nueva línea en un archivo, entonces
.¿Esperando un cambio en un sistema de archivos? Entonces use eg
.Y hay otras opciones, dependiendo de lo que quiera decir con "esperar".
fuente