Sé que puedo esperar que una condición se haga realidad en bash haciendo:
while true; do
test_condition && break
sleep 1
done
Pero crea 1 subproceso en cada iteración (suspensión). Podría evitarlos haciendo:
while true; do
test_condition && break
done
Pero usa mucha CPU (espera ocupada). Para evitar subprocesos y esperas ocupadas, se me ocurrió la solución a continuación, pero me parece fea:
my_tmp_dir=$(mktemp -d --tmpdir=/tmp) # Create a unique tmp dir for the fifo.
mkfifo $my_tmp_dir/fifo # Create an empty fifo for sleep by read.
exec 3<> $my_tmp_dir/fifo # Open the fifo for reading and writing.
while true; do
test_condition && break
read -t 1 -u 3 var # Same as sleep 1, but without sub-process.
done
exec 3<&- # Closing the fifo.
rm $my_tmp_dir/fifo; rmdir $my_tmp_dir # Cleanup, could be done in a trap.
Nota: en el caso general, no puedo simplemente usarlo read -t 1 var
sin el fifo, porque consumirá stdin y no funcionará si stdin no es un terminal o una tubería.
¿Puedo evitar los subprocesos y la espera ocupada de una manera más elegante?
bash
shell-script
sleep
jfg956
fuente
fuente
true
es incorporado y no crea un subproceso en bash. La espera ocupada siempre será mala.true
, pregunta actualizada.read -t 1 var
.sleep
como en el primer ejemplo. El segundo, si bien puede funcionar, no va a ser fácil para nadie en el futuro. El código simple también tiene un mayor potencial para ser seguro.Respuestas:
En las versiones más recientes de
bash
(al menos v2), los builtins se pueden cargar (víaenable -f filename commandname
) en tiempo de ejecución. Un número de tales construcciones cargables también se distribuye con las fuentes bash, y sesleep
encuentra entre ellas. La disponibilidad puede variar de un sistema operativo a otro (e incluso de máquina a máquina), por supuesto. Por ejemplo, en openSUSE, estos componentes internos se distribuyen a través del paquetebash-loadables
.Editar: arregle el nombre del paquete, agregue la versión mínima de bash.
fuente
sleep
como un archivo incorporado. Gracias.Crear muchos subprocesos es algo malo en un bucle interno. Crear un
sleep
proceso por segundo está bien. No hay nada malo conSi realmente desea evitar el proceso externo, no necesita mantener abierto el Fifo.
fuente
mkdir
como está hechomktemp
(si no, es una condición de carrera)). También es cierto lowhile ! test_condition;
que es mejor que mi solución inicial.Recientemente tuve la necesidad de hacer esto. Se me ocurrió la siguiente función que permitirá que bash duerma para siempre sin llamar a ningún programa externo:
NOTA: Publiqué previamente una versión de esto que abriría y cerraría el descriptor de archivo cada vez, pero descubrí que en algunos sistemas que lo hacen cientos de veces por segundo eventualmente se bloqueará. Por lo tanto, la nueva solución mantiene el descriptor de archivo entre llamadas a la función. Bash lo limpiará a la salida de todos modos.
Esto se puede llamar como / bin / sleep, y se dormirá durante el tiempo solicitado. Llamado sin parámetros, se colgará para siempre.
Hay una reseña con detalles excesivos en mi blog aquí.
fuente
read -t 10 < <(:)
regresa de inmediato mientrasread -t 10 <> <(:)
espera los 10 segundos completos, pero aún no lo entiendo.read -t 10 <> <(:)
¿ En qué significa<>
?En
ksh93
omksh
,sleep
hay una concha incorporada, por lo que una alternativa podría ser usar esas conchas en lugar debash
.zsh
también tiene unzselect
incorporado (cargado conzmodload zsh/zselect
) que puede dormir durante un número determinado de centésimas de segundo conzselect -t <n>
.fuente
Como dijo el usuario yoi , si en su script se abre stdin , entonces en lugar de dormir 1 simplemente puede usar:
En Bash versión 4.1 y posteriores, puede usar el número flotante, p. Ej.
read -t 0.3 ...
Si en un script, stdin está cerrado (se llama script
my_script.sh < /dev/null &
), entonces necesita usar otro descriptor abierto, que no produce salida cuando se ejecuta la lectura , por ejemplo. stdout :Si en un script todo el descriptor está cerrado ( stdin , stdout , stderr ) (por ejemplo, porque se llama como daemon), entonces necesita encontrar cualquier archivo existente que no produzca resultados:
fuente
read -t 1 3<&- 3<&0 <&3
es el mismo queread -t 0
. Es solo leer de stdin con tiempo de espera.Esto funciona desde un shell de inicio de sesión, así como desde un shell no interactivo.
fuente
read -t 10 <> <(:)
.¿Realmente necesitas un quince? Redirigir stdin a otro descriptor de archivo también debería funcionar.
Inspirado por: Leer la entrada en bash dentro de un bucle while
fuente
Una ligera mejora en las soluciones mencionadas anteriormente (en las que he basado esto).
Se redujo la necesidad de un fifo y, por lo tanto, no hay que limpiar.
fuente
read -t 10 <> <(:)
.