Cómo obtener una lista de todos los procesos secundarios generados por un script

9

Contexto:

Los usuarios me proporcionan sus scripts personalizados para ejecutar. Estos scripts pueden ser de cualquier tipo, como scripts para iniciar múltiples programas GUI, servicios de back-end. No tengo control sobre cómo se escriben los guiones. Estos scripts pueden ser de tipo de bloqueo, es decir, la ejecución espera hasta que todos los procesos secundarios (programas que se ejecutan secuencialmente) salen

#exaple of blocking script
echo "START"
first_program 
second_program 
echo "DONE"

o tipo no bloqueante, es decir, aquellos que bifurcan el proceso secundario en segundo plano y salen como

#example of non-blocking script
echo "START"
first_program &
second_program &
echo "DONE"

¿Qué estoy tratando de lograr?

Los scripts proporcionados por el usuario pueden ser de cualquiera de los dos tipos anteriores o una combinación de ambos. Mi trabajo es ejecutar el script y esperar hasta que todos los procesos iniciados por él salgan y luego apague el nodo. Si es de tipo de bloqueo, el caso es simple, es decir, obtenga el PID del proceso de ejecución del script y espere hasta que ps -ef | grep -ef PID no tenga más entradas. Los scripts sin bloqueo son los que me están dando problemas

¿Hay alguna manera de obtener una lista de PID de todos los procesos secundarios generados por la ejecución de un script? Cualquier sugerencia o sugerencia será muy apreciada

irraju
fuente
No creo que sea posible después de que el script principal haya finalizado, a menos que pueda capturar el PID del padre. Si está iniciando los scripts, puede envolverlos en algo como lo pid$(foo.sh; echo $!)que le dará el PID foo.shpara que luego pueda usar ps --ppid. ¿Eso funcionará?
terdon
2
¿Los scripts deben ejecutarse bajo el UID del usuario autor? Si no, ¿puede crear un usuario ficticio solo para este propósito? Ni siquiera lo necesitarías grep, solo ps –udummy_user. Además, observe los grupos de procesos.
Scott, el
Este es más un tipo de solución alternativa que una solución para su pregunta inicial: abra una nueva sesión de bash. Puede enumerar todos los procesos generados desde este shell pssin ningún argumento (debe ser solo bashy psal principio). Comience su secuencia de comandos allí. Después de que termine, espere hasta que ps | wc -lalcance el valor esperado.
Tim

Respuestas:

8

Para responder su pregunta directamente, el comando

jobs -p

le da la lista de todos los procesos secundarios.

Alternativa # 1

Pero en su caso, podría ser más fácil usar el comando waitsin ningún parámetro:

first_program &
second_program &
wait

Esto esperará hasta que TODOS los procesos secundarios hayan terminado.

Alternativa # 2

Otra alternativa es usar $!para obtener el PID del último programa y tal vez acumular en una variable, de esta manera:

pids=""
first_program &
pids="$pids $!"
second_program &
pids="$pids $!"

y luego use wait with that (esto es en caso de que solo quiera esperar un subconjunto de sus procesos secundarios):

wait $pids

Alternativa # 3

O, si desea esperar solo hasta que CUALQUIER proceso haya terminado, puede usar

wait -n $pids

Información adicional

Si desea un sigterm en su script bash para cerrar sus procesos secundarios también, necesitará propagar la señal con algo como esto (ponga esto en algún lugar en la parte superior, antes de comenzar cualquier proceso):

trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT
Vlad A Ionescu
fuente
1

Gracias a todos por sus respuestas. Tengo la solución en stackoverflow

Puede usar esperar para esperar a que se completen todos los procesos en segundo plano iniciados por userscript. Dado que wait solo funciona en los elementos secundarios del shell actual, deberá obtener su script en lugar de ejecutarlo como un proceso separado.

(fuente script de usuario; espera)

Obtener el script en una subshell explícita debería simular iniciar un nuevo proceso lo suficientemente cerca. Si no es así, también puede poner en segundo plano la subshell, lo que obliga a iniciar un nuevo proceso y luego esperar a que se complete.

(fuente usercript; esperar) y esperar

Aquí está el enlace para la respuesta original de @chepner: /programming/18663196/how-to-get-list-of-all-child-process-spawned-by-a-script/18663969?noredirect = 1 # 18663969

irraju
fuente
3
También pensé en esto, pero esta solución falla cuando el script de usuario inicia un subíndice en segundo plano que luego inicia otro script en segundo plano. Su waitcomando luego esperará a los hijos de usercript pero no a sus nietos.
Tim
@Tim Acabo de darme cuenta de que :(
irraju