¿Cómo duermo un milisegundo en bash o ksh?

128

dormir es un comando muy popular y podemos comenzar a dormir desde 1 segundo:

# wait one second please 
sleep 1

pero, ¿cuál es la alternativa si necesito esperar solo 0.1 segundos o entre 0.1 y 1 segundo?

  • comentario: en linux u OS X sleep 0.XXXfunciona bien, pero en solaris sleep 0.1o sleep 0.01- sintaxis ilegal
yael
fuente
2
¿Puedo preguntarte por qué quieres dormir durante 1 ms?
Tom O'Connor
1
Sí, por supuesto, en mi script bash agrego "sleep 1", en algunas líneas, pero el script se ejecuta muy lentamente, por lo que después de alguna conclusión calculo que sleep 0.1 también trae buenos resultados y más rápido. Sobre el retraso, necesito un retraso para poder para resolver el problema de ssh en mi script bash, realizo el inicio de sesión paralelo de ssh en algunas máquinas de forma anticipada y sin demora no funcionará, como saben por mi pregunta, la demora debería encajar tanto en Linux como en Solaris
yael
3
Cualquiera sea la solución que elija, tenga en cuenta que un script de shell no será muy preciso en términos de tiempo.
scai
¿Qué tal hacer algo que lleva muy poco tiempo ejecutar, pero no hace nada ... comoecho "" >/dev/null
Tom O'Connor
Buena idea, pero ¿cómo tarda este comando? , Necesito 0.1 ms, no menos que eso - :)
yael

Respuestas:

68

Bash tiene una suspensión "cargable" que admite segundos fraccionarios y elimina los gastos generales de un comando externo:

$ cd bash-3.2.48/examples/loadables
$ make sleep && mv sleep sleep.so
$ enable -f sleep.so sleep

Entonces:

$ which sleep
/usr/bin/sleep
$ builtin sleep
sleep: usage: sleep seconds[.fraction]
$ time (for f in `seq 1 10`; do builtin sleep 0.1; done)
real    0m1.000s
user    0m0.004s
sys     0m0.004s

La desventaja es que es posible que los archivos cargables no se proporcionen con su bashbinario, por lo que necesitaría compilarlos usted mismo como se muestra (aunque en Solaris no sería necesariamente tan simple como arriba).

A partir debash-4.4 (septiembre de 2016), todas las herramientas cargables ahora están compiladas e instaladas de forma predeterminada en plataformas que lo admiten, aunque están compiladas como archivos de objetos compartidos separados y sin .sosufijo. A menos que su distribución / sistema operativo haya hecho algo creativo, debería poder hacer lo siguiente:

[ -z "$BASH_LOADABLES_PATH" ] &&
  BASH_LOADABLES_PATH=$(pkg-config bash --variable=loadablesdir 2>/dev/null)  
enable -f sleep sleep

(La página del manual implica que BASH_LOADABLES_PATHse configura automáticamente, creo que este no es el caso en la distribución oficial a partir de 4.4.12. Si se configura correctamente y solo enable -f filename commandnamecuando sea necesario).

Si eso no es adecuado, lo siguiente más fácil de hacer es construir u obtener sleepde coreutils de GNU, esto es compatible con la función requerida. El sleepcomando POSIX es mínimo, las versiones anteriores de Solaris implementaron solo eso. Solaris 11 sleep hace apoyar fracciones de segundo.

Como último recurso, puede usar perl(o cualquier otra secuencia de comandos que tenga a mano) con la advertencia de que la inicialización del intérprete puede ser comparable al tiempo de sueño previsto:

$ perl -e "select(undef,undef,undef,0.1);"
$ echo "after 100" | tclsh
Sr. púrpura
fuente
2
Ah, ya que estás usando expect, probablemente puedas usar " after N", donde N es milisegundos, directamente en tu script.
Sr.Spuratic
use usleepcomo @Luis Vazquez y @sebix write
Ilan.K
Apple MacOS tiene suspensión BSD, que también admite segundos fraccionarios
roblogic
125

La documentación para el sleepcomando de coreutils dice:

Las implementaciones históricas del sueño han requerido que ese número sea un número entero, y solo aceptaron un solo argumento sin sufijo. Sin embargo, la suspensión de GNU acepta números arbitrarios de coma flotante. Ver punto flotante .

Por lo tanto, puede usar sleep 0.1, sleep 1.0e-1y argumentos similares.

scai
fuente
1
vea mi comentario sobre SOLARIS OS
yael
¿Te confundiste es y no es ?
scai
ver mi actualización en mi cita
yael
1
Yael, creo que todavía hay demasiados puntos negativos en tu pregunta; ¿estás seguro de que quieres decir "sintaxis no ilegal"?
MadHatter
por ejemplo, ejecuto en solaris 10 esto: # sleep 0.1 sleep: mal carácter en la discusión, sobre linux sleep 0.1 funciona bien
yael
58

Sleep acepta números decimales para que pueda desglosar esto como:

1/2 de segundo

 sleep 0.5

1/100 de segundo

sleep 0.01

Entonces por un milisegundo querrías

sleep 0.001
colealtdelete
fuente
44
También puede colocar el cero inicial antes del punto decimal. p.ej. sleep .5
Mike Causer
Hable acerca de que todos los demás lo complicaron demasiado ...
Martin
1
@MikeCauser lleva los ceros mucho más legibles y la intención de la señal al lector del código más tarde. también mejor cuando realmente haces matemáticas.
Alexander Mills
11

Pruebe esto para determinar la precisión:

    time sleep 0.5      # 500 milliseconds (1/2 of a second)
    time sleep 0.001    # 1 millisecond (1/1000 of a second)
    time sleep 1.0      # 1 second (1000 milliseconds)

Combinación de la solución de mr.spuratic y la solución de coles .

dsrdakota
fuente
8

Simplemente puede usar usleep. Toma microsegundos (= 1e-6 segundos) como parámetro, por lo que para dormir 1 milisegundo ingresaría:

usleep 1000
Luis Vázquez
fuente
1
$ usleep No command 'usleep' found, did you mean: Command 'sleep' from package 'coreutils' (main) usleep: command not found
Bulletmagnet
No, me refiero a usleepparte del initscriptspaquete que es estándar al menos en todas las distribuciones derivadas de Red Hat; incluyendo al menos RHEL, CentOS, Fedora, Mageia / Mandriva y SuSE. Aquí un ejemplo: `` ``
Luis Vazquez
1
Aquí hay una muestra de ejemplo que se ejecuta en CentOS 7: `` $ which usleep / usr / bin / usleep $ rpm -qf / usr / bin / usleep initscripts-9.49.37-1.el7_3.1.x86_64 `` `Para resumir : - sleep(desde coreutils ) funciona con segundos - usleep(desde initscripts ) funciona con microsegundos
Luis Vazquez
4

Tuve el mismo problema (sin shell usleep en Solaris), así que escribí el mío así:

  #include "stdio.h"
  int main(int argc, char **argv) {
     if(argc == 2) { usleep(atoi(argv[1])); }
     return 0;
}

No verifica los argumentos: recomendaría uno correctamente escrito si desea conservarlo, pero eso (gcc usleep.c -o usleep) lo sacará de un agujero.

jrichemont
fuente
1
Al menos, podría cambiar esa usleep()llamada simple if(argc == 1) { usleep(atoi(argv[1])); }para evitar la indexación fuera de los límites de la matriz, lo que puede conducir a una cantidad de comportamientos inesperados.
un CVn
@aCVn Es en realidad if (argc == 2) { usleep(atoi(argv[1])); }...
Anillo Ø
También tenga en cuenta que la usleepunidad es μs, por lo que para esperar 1 segundo, debe proporcionar un argumento 1000000.
Anillo Ø
@ RingØ Derecha. Estúpido error, buena captura.
un CVn
atoi()Es una elección horrible convertir una cadena en un int. ¿Qué atoi( "STRING" )devuelve? atoi()no tiene forma de devolver ningún error.
Andrew Henle