while second script for linux bash sleep infinite

linux - second - Bash: sueño infinito(bloqueo infinito)



sleep linux (9)

tail no bloquea

Como siempre: para todo hay una respuesta que es corta, fácil de entender, fácil de seguir y completamente incorrecta. Aquí tail -f /dev/null pertenece a esta categoría;)

Si lo miras con strace tail -f /dev/null , notarás que esta solución está lejos de ser bloqueante. Probablemente sea incluso peor que la solución de sleep en la pregunta, ya que utiliza (en Linux) recursos preciosos como el sistema inotify . También otros procesos que escriben en /dev/null hacen tail bucle. (En mi Ubuntu64 16.10 esto agrega varias 10 llamadas de sistema por segundo en un sistema ya ocupado).

La pregunta era por un comando de bloqueo

Desafortunadamente, no existe tal cosa.

Leer: no sé cómo archivar esto con el shell directamente.

Todo (incluso sleep infinity ) puede ser interrumpido por alguna señal. Entonces, si quiere estar realmente seguro de que no regresa de manera excepcional, debe ejecutarse en un ciclo, como lo hizo para sleep . Tenga en cuenta que (en Linux) /bin/sleep aparentemente tiene un límite de 24 días (eche un vistazo al strace sleep infinity ), por lo tanto, lo mejor que puede hacer es:

while :; do sleep 2073600; done

(Tenga en cuenta que creo que el sleep repite internamente en valores superiores a 24 días, pero esto significa que no está bloqueando, es muy lento y, por lo tanto, ¿por qué no se mueve este bucle hacia el exterior?)

.. pero puedes acercarte bastante con un fifo sin nombre

Puedes crear algo que realmente bloquee mientras no haya señales enviadas al proceso. A continuación se usan los bash 4 , 2 PID y 1 fifo :

bash -c ''coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait''

Puedes comprobar que esto realmente bloquea con strace si te gusta:

strace -ff bash -c ''..see above..''

Cómo se construyó esto

read bloques si no hay datos de entrada (ver algunas otras respuestas). Sin embargo, el tty (también conocido como stdin ) generalmente no es una buena fuente, ya que se cierra cuando el usuario cierra la sesión. También podría robar alguna entrada de la tty . No está bien.

Para hacer el bloque de read , tenemos que esperar algo como un fifo que nunca devolverá nada. En bash 4 hay un comando que puede proporcionarnos exactamente tal fifo : coproc . Si también esperamos la read bloqueo (que es nuestro coproc ), hemos terminado. Lamentablemente, esto necesita mantener abiertos dos PID y un fifo .

Variante con un nombre fifo

Si no te molestas en utilizar un fifo nombre, puedes hacerlo de la siguiente manera:

mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"

No utilizar un bucle en la lectura es un poco descuidado, pero puede reutilizar esta fifo con la frecuencia que desee y realizar la read con touch "$HOME/.pause.fifo" (si hay más de una lectura en espera) , todos terminan a la vez).

O utilice el syscall de pause() Linux pause()

Para el bloqueo infinito hay una llamada al kernel de Linux, llamada pause() , que hace lo que queremos: Espere por siempre (hasta que llegue una señal). Sin embargo, no hay un programa de espacio de usuario para esto (todavía).

do

Crear tal programa es fácil. Aquí hay un fragmento para crear un programa Linux muy pequeño llamado pause que se detiene indefinidamente (necesita diet , gcc , etc.):

printf ''#include <unistd.h>/nint main(){for(;;)pause();}'' > pause.c; diet -Os cc pause.c -o pause; strip -s pause; ls -al pause

python

Si no desea compilar algo usted mismo, pero tiene instalado python , puede usarlo en Linux:

python -c ''while 1: import ctypes; ctypes.CDLL(None).pause()''

(Nota: Use exec python -c ... para reemplazar el shell actual, esto libera un PID. La solución se puede mejorar también con algunos redireccionamientos de IO, liberando los FD no utilizados. Esto depende de usted.)

Cómo funciona esto (creo): ctypes.CDLL(None) carga la biblioteca C estándar y ejecuta la función pause() dentro de un bucle adicional. Menos eficiente que la versión C, pero funciona.

Mi recomendación para ti:

Quédate en el sueño de bucle. Es fácil de entender, muy portátil y bloquea la mayor parte del tiempo.

Uso startx para iniciar X que evaluará mi .xinitrc . En mi .xinitrc inicio mi administrador de ventanas usando /usr/bin/mywm . Ahora, si elimino mi WM (para poder probar alguna otra WM), X terminará también porque la secuencia de comandos .xinitrc llegó a EOF. Así que agregué esto al final de mi .xinitrc :

while true; do sleep 10000; done

De esta forma, X no terminará si elimino mi WM. Ahora mi pregunta: ¿cómo puedo hacer un sueño infinito en lugar de dormir en bucle? ¿Hay algún comando que pueda congelar el script?

Atentamente


¿Qué hay de enviar un SIGSTOP a sí mismo?

Esto debería detener el proceso hasta que se reciba SIGCONT. Cuál es tu caso: nunca.

kill -STOP "$$"; # grace time for signal delivery sleep 60;


En lugar de matar al administrador de ventanas, intente ejecutar el nuevo con -replace o -replace si está disponible.


Recientemente tuve la necesidad de hacer esto. Se me ocurrió la siguiente función que permitirá a bash dormir para siempre sin llamar a ningún programa externo:

snore() { [[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:) read ${1:+-t "$1"} -u $_snore_fd || : }

NOTA: Anteriormente publiqué una versión de esto que abriría y cerraría el descriptor de archivo cada vez, pero descubrí que en algunos sistemas esto cientos de veces se bloquea. Por lo tanto, la nueva solución mantiene el descriptor de archivo entre las llamadas a la función. Bash lo limpiará a la salida de todos modos.

Esto se puede llamar como / bin / sleep, y duerme durante el tiempo solicitado. Llamado sin parámetros, se colgará para siempre.

snore 0.1 # sleeps for 0.1 seconds snore 10 # sleeps for 10 seconds snore # sleeps forever

Hay un escrito con detalles excesivos en mi blog aquí


TL; DR: sleep infinity realidad duerme el tiempo máximo permitido, que es finito.

Preguntándome por qué esto no está documentado en ninguna parte, me molesté en leer las fuentes de GNU coreutils y encontré que se ejecuta aproximadamente de la siguiente manera:

  1. Use strtod de C stdlib en el primer argumento para convertir ''infinito'' a doble precisión. Entonces, asumiendo la doble precisión IEEE 754, el valor infinito positivo de 64 bits se almacena en la variable de seconds .
  2. Invoque xnanosleep(seconds) ( encontrado en gnulib ), esto a su vez invoca dtotimespec(seconds) (también en gnulib) para convertir de double a struct timespec .
  3. struct timespec es solo un par de enteros: parte entera (en segundos) y parte fraccionaria (en nanosegundos). Naïvely convertir infinito positivo a entero produciría un comportamiento indefinido (véase §6.3.1.4 del estándar C), por lo que truncará a TYPE_MAXIMUM (time_t) .
  4. El valor real de TYPE_MAXIMUM (time_t) no está en el estándar (incluso sizeof(time_t) no lo está); entonces, por el bien del ejemplo, vamos a elegir x86-64 de un kernel de Linux reciente.

Esto es TIME_T_MAX en el kernel de Linux, que está definido ( time.h ) como:

(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)

Tenga en cuenta que time_t es __kernel_time_t y time_t es long ; se usa el modelo de datos LP64, por lo que sizeof(long) es 8 (64 bits).

Que produce: TIME_T_MAX = 9223372036854775807 .

Es decir: el sleep infinite da como resultado un tiempo de sueño real de 9223372036854775807 segundos (10 ^ 11 años). Y para sistemas de 32 bits de Linux ( sizeof(long) es 4 (32 bits)): 2147483647 segundos (68 años; consulte también el problema del año 2038).

Editar : al parecer, la función de nanoseconds llamada no es directamente el syscall, sino un contenedor dependiente del sistema operativo (también se define en gnulib ).

Como resultado, hay un paso adicional: para algunos sistemas donde HAVE_BUG_BIG_NANOSLEEP es true la suspensión se trunca a 24 días y luego se llama en un bucle. Este es el caso para algunas (¿o todas?) Distros de Linux. Tenga en cuenta que este contenedor no se puede utilizar si una prueba de tiempo de configuración tiene éxito ( source ).

En particular, eso sería 24 * 24 * 60 * 60 = 2073600 seconds (más 999999999 nanosegundos); pero esto se llama en un ciclo para respetar el tiempo de sueño total especificado. Por lo tanto, las conclusiones anteriores siguen siendo válidas.

En conclusión, el tiempo de inactividad resultante no es infinito, pero lo suficientemente alto para todos los propósitos prácticos , incluso si el lapso de tiempo real resultante no es portátil; eso depende del sistema operativo y la arquitectura.

Para responder a la pregunta original, esto es obviamente lo suficientemente bueno, pero si por alguna razón (un sistema muy limitado en recursos) realmente quieres evitar un temporizador de cuenta atrás adicional inútil, supongo que la alternativa más correcta es usar el método de cat descrito en otro respuestas


Tal vez esto parezca feo, pero ¿por qué no simplemente ejecutar cat y dejar que espere la entrada para siempre?


sleep infinity hace exactamente lo que sugiere y funciona sin abuso de gatos.


sleep infinity parece más elegante, pero a veces no funciona por alguna razón. En ese caso, puede probar otros comandos de bloqueo como cat , read , tail -f /dev/null , grep a etc.


while :; do read; done

sin esperar el proceso de dormir del niño.