¿Hay alguna función integrada en Bash para esperar a que finalice un proceso?
El wait
comando solo permite esperar a que finalicen los procesos secundarios. Me gustaría saber si hay alguna forma de esperar a que termine algún proceso antes de continuar con cualquier script.
Una forma mecánica de hacer esto es la siguiente, pero me gustaría saber si hay alguna característica integrada en Bash.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
Respuestas:
Esperar a que termine cualquier proceso
Linux:
Darwin (requiere que
$pid
tenga archivos abiertos):Con tiempo de espera (segundos)
Linux:
Darwin (requiere que
$pid
tenga archivos abiertos):fuente
tail
haría esto.tail
funciona bajo el capó sondeandokill(pid, SIG_0)
a un proceso (descubierto usandostrace
).+r 1
es el tiempo de espera, personalmente estoy buscando una solución para MacOS que no use el sondeo.tail
tiene la lineakill (pid, 0) != 0 && errno != EPERM
.caffeinate -w $pid
hará el truco.No hay incorporado. Use
kill -0
en un bucle para una solución viable:O como una línea más simple para un uso fácil y único:
Como señalaron varios comentaristas, si desea esperar procesos a los que no tiene el privilegio de enviar señales, debe encontrar otra forma de detectar si el proceso se está ejecutando para reemplazar la
kill -0 $pid
llamada. En Linux,test -d "/proc/$pid"
funciona, en otros sistemas puede que tenga que usarpgrep
(si está disponible) o algo asíps | grep "^$pid "
.fuente
sleep 0.5
, el proceso con$pid
puede morir y se puede crear otro proceso con el mismo$pid
. Y terminaremos esperando 2 procesos diferentes (o incluso más) con el mismo$pid
.Encontré que "kill -0" no funciona si el proceso es propiedad de root (u otro), así que usé pgrep y se me ocurrió:
Esto tendría la desventaja de que probablemente coincida con los procesos de zombies.
fuente
kill(pid, sig=0)
falla si el proceso de la persona que llama no tiene el privilegio de matar. Por lo tanto, / bin / kill -0 y "kill -0" (bash incorporado) también fallan en la misma condición.Este bucle de script bash finaliza si el proceso no existe o si es un zombie.
EDITAR : El guión anterior fue dado a continuación por Rockallite . ¡Gracias!
Mi respuesta original a continuación funciona para Linux, confiando en
procfs
ie/proc/
. No sé su portabilidad:No se limita al shell, pero los sistemas operativos en sí no tienen llamadas al sistema para ver la finalización del proceso que no es secundario.
fuente
grep /proc/$PID/status
con comillas dobles (bash: test: argument expected
)while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do sleep 1; done
ps
ni-p
os=
se soportanFreeBSD y Solaris tienen esta práctica
pwait(1)
utilidad, que hace exactamente lo que quieres.Creo que otros sistemas operativos modernos también tienen las llamadas necesarias al sistema (MacOS, por ejemplo, implementa BSD
kqueue
), pero no todos lo hacen disponible desde la línea de comandos.fuente
> BSD and Solaris
: Inspeccionar los tres grandes BSD que vienen a la mente; ni OpenBSD ni NetBSD tienen esta función (en sus páginas de manual), solo FreeBSD la tiene, como puede comprobar fácilmente en man.openbsd.org .kqueue
, por lo que compilar FreeBSDpwait(1)
sería trivial, sin embargo. ¿Por qué no los demás BSD importar la función me escapa ...plink me@oracle box -pw redacted "pwait 6998";email -b -s "It's done" etc
solo me permitió irme a casa ahora en lugar de dentro de horas.Desde la página de manual de bash
fuente
wait
sin argumentos bloqueará el proceso hasta que finalice cualquier proceso hijo . Honestamente, no veo ningún punto para esperar ningún proceso, ya que siempre están sucediendo procesos del sistema.sleep 1000
ctrl-z
wait [sleep pid]
regresa inmediatamenteTodas estas soluciones se prueban en Ubuntu 14.04:
Solución 1 (usando el comando ps): solo para agregar a la respuesta de Pierz, sugeriría:
En este caso,
grep -vw grep
asegura que grep solo coincida con nombre_proceso y no grep en sí mismo. Tiene la ventaja de admitir los casos en que process_name no está al final de una línea enps axg
.Solución 2 (usando el comando superior y el nombre del proceso):
Reemplace
process_name
con el nombre del proceso que aparece entop -n 1 -b
. Por favor, mantenga las comillas.Para ver la lista de procesos que espera a que finalicen, puede ejecutar:
Solución 3 (usando el comando superior y la ID del proceso):
Reemplace
process_id
con el ID de proceso de su programa.fuente
grep -v grep
tubería es un antipatrón masivo, y esto presupone que no tiene procesos no relacionados con el mismo nombre. Si conoce los PID en su lugar, esto podría adaptarse a una solución que funcione correctamente.-w
para evitar el problemagrep -v grep
hasta cierto punto . También agregué dos soluciones más basadas en tu comentario.De acuerdo, parece que la respuesta es: no, no hay una herramienta integrada.
Después de ajustar
/proc/sys/kernel/yama/ptrace_scope
a0
, es posible utilizar elstrace
programa. Se pueden usar más interruptores para silenciarlo, de modo que realmente espere pasivamente:fuente
Operation not permitted
para la segunda instancia de strace); puedes confirmar eso?(...)"tracee" always means "(one) thread"
(y confirmo el error que mencionas). Para permitir que más procesos esperen de esta manera, tendrías que hacer una cadena.Solución de bloqueo
Use el
wait
en un bucle para esperar a que finalicen todos los procesos:Esta función se cerrará de inmediato, cuando todos los procesos se terminaron. Esta es la solución más eficiente.
Solución no bloqueante
Utilice el
kill -0
en un bucle, para esperar la finalización de todos los procesos + hacer cualquier cosa entre comprobaciones:El tiempo de reacción disminuyó a
sleep
tiempo, ya que hay que evitar el uso elevado de CPU.Un uso realista:
En espera de terminar todos los procesos + informar al usuario sobre todos los PID en ejecución.
Notas
Estas funciones obtienen PID a través de argumentos
$@
como BASH array.fuente
Tuve el mismo problema, resolví el problema eliminando el proceso y luego esperando que cada proceso terminara de usar el sistema de archivos PROC:
fuente
No hay una función integrada que espere a que finalice cualquier proceso.
Podrías enviar
kill -0
a cualquier PID encontrado, para que no te desconcierten los zombis y las cosas que aún serán visiblesps
(mientras recuperas la lista PID usandops
).fuente
Use inotifywait para monitorear algunos archivos que se cierran cuando finaliza su proceso. Ejemplo (en Linux):
-e especifica el evento a esperar, -q significa salida mínima solo en la terminación. En este caso será:
Se puede usar un solo comando de espera para esperar múltiples procesos:
La cadena de salida de inotifywait le dirá qué proceso finalizó. Esto solo funciona con archivos 'reales', no con algo en / proc /
fuente
En un sistema como OSX, es posible que no tenga pgrep, por lo que puede probar esta aproximación cuando busque procesos por nombre:
El
$
símbolo al final del nombre del proceso garantiza que grep solo coincida con nombre_proceso al final de la línea en la salida ps y no a sí mismo.fuente
/dev/null
,-q
debe usarse congrep
. Otra instancia del proceso puede haber comenzado mientras su ciclo estaba durmiendo y nunca lo sabrá ...-q
sugerencia es válida, como mencioné en mi respuesta específicamente, la terminación$
significa que grep no coincidirá con el nombre "en algún lugar de la línea de comando" ni con el mismo. ¿Realmente lo has probado en OSX?La solución de Rauno Palosaari
Timeout in Seconds
Darwin
es una excelente solución para un sistema operativo tipo UNIX que no tiene GNUtail
(no es específico paraDarwin
). Pero, dependiendo de la antigüedad del sistema operativo tipo UNIX, la línea de comandos que se ofrece es más compleja de lo necesario y puede fallar:En al menos un UNIX antiguo, el
lsof
argumento+r 1m%s
falla (incluso para un superusuario):El
m%s
es una especificación de formato de salida. Un postprocesador más simple no lo requiere. Por ejemplo, el siguiente comando espera en PID 5959 hasta cinco segundos:En este ejemplo, si el PID 5959 sale por sí solo antes de que transcurran los cinco segundos,
${?}
es0
. Si no${?}
regresa1
después de cinco segundos.Vale la pena señalar expresamente que en
+r 1
,1
es el intervalo de sondeo (en segundos), por lo que puede cambiarse para adaptarse a la situación.fuente