%20no%20funciona%20en%20el%20script.png)
Estoy intentando realizar un bucle hasta que se complete un proceso en segundo plano (iniciado anteriormente en el script). Un caso de prueba fácilmente reproducible es:
ping -c 10 localhost &>/dev/null &
En la línea de comando, puedo realizar un bucle while [[ -n $(jobs) ]]
(mientras $(jobs)
no es nulo).
$ ping -c 10 localhost &>/dev/null &
[1] 19078
$ while [[ -n $(jobs) ]]; do echo -n .; sleep 1; done
.........[1]+ Done ping -c 5 localhost &> /dev/null
Sin embargo, las mismas dos líneas en un script seguirán imprimiendo .
s hasta que presione Ctrl-C
.
Curiosamente, si llamo jobs
dentro del bucle, el script finaliza como se esperaba.
$ ./background-ping.sh
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Done ping -c 5 localhost &> /dev/null
Soy consciente de que existen otras formas de verificar si el trabajo en segundo plano está completo (por ejemplo, verificar /proc
), pero quiero saber por qué la verificación jobs
no funciona como se esperaba.
Respuesta1
Si entiendo su problema, sus 2 líneas no se detendrán en un script.
Eso es lo que hice en el mío:
ping -c 5 google.com &>/dev/null &
while [[ -n $(jobs -r) ]]; do echo -n "."; sleep 1; done
jobs -r
comprueba los procesos en ejecución y la llamada a mi script funciona como se esperaba, el script se detiene cuando finaliza el ping.
EDITAR: Creo que en un script el proceso principal se conoce como proceso en ejecución y por eso jobs
sigo pensando que hay un proceso en ejecución. Esa es una hipótesis
¿Es esa la respuesta? (o tal vez realmente no entiendo lo que quieres decir, mi pobre inglés puede ser el problema...)
Respuesta2
Siempre que tenga problemas como este, siempre debe intentar imprimir sus variables para comprender lo que está sucediendo. En este caso, jobs
también devuelve trabajos terminados. Si ejecutas esto:
ping -c 5 localhost &>/dev/null &
while [[ -n $(jobs | tee -a temp) ]]; do
echo -n .;
sleep 1;
done
Verá el siguiente resultado en temp
:
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[...]
Entonces, la salida de jobs
aquí nunca está vacía. Incluso cuando el trabajo finaliza, jobs
todavía devuelve el Done
mensaje. Es por eso que la solución de Metal3d jobs -r
funcionó.
Lo que es más confuso es por qué ejecutar jobs
dentro del bucle hace que funcione correctamente. La respuesta tendrá algo que ver con el hecho de que while [[ -n $(jobs) ]]
se ejecuta jobs
en una subcapa separada, pero no estoy seguro de los detalles. Tengopublicó una preguntasobre esto en U&L si alguien está interesado.
Respuesta3
Puede utilizar wait
un comando que espera a que se detengan los trabajos en segundo plano.
Ejemplo:
$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+ Done ping -c 10 localhost &>/dev/null
El comando de espera se bloquea y cuando ping
finaliza, se libera el mensaje y luego se imprime un mensaje.
Puedes usarlo con varios comandos:
$ ping -c 5 localhost &>/dev/null & ping -c 5 facebook.com &>/dev/null &
[1] 29867
[2] 29868
$ wait
[1]- Done ping -c 5 localhost &>/dev/null
[2]+ Done ping -c 5 facebook.com &>/dev/null