Ejecutar múltiples programas en segundo plano y verificar su valor de retorno

Ejecutar múltiples programas en segundo plano y verificar su valor de retorno

supongamos que quiero ejecutar algunos (digamos, tres) programas a la vez, como este

program1 & program2 & program3 &

Si quiero saber sus pid's, creo que la mejor manera es almacenarlos, así

program1 &
pid1=$!
program2 &
pid2=$!
...

Pero ahora, ¿qué pasa si quiero saber si han finalizado y, de ser así, qué valor me devolvieron? Algo como esto:

if [ program1 has ended ]; then
    do something with its return value
fi

Cualquier ayuda será apreciada.

Respuesta1

# launch child process in background
launch_child_process &

# grab child's pid and store it (use array if several)
pid=$!

# later, wait for termination
wait $pid
# show return code from wait, which is actually the return code of the child
echo "Child return code:" $?

Con varios hijos, por supuesto, puede realizar un bucle para esperar en cada pid y recopilar el código de retorno correspondiente. Sales de ese bucle cuando termina el último hijo.

Respuesta2

Una solución sencilla es escribir un mensaje en un archivo de registro.

Digamos, para el programa 1, haga algo como:

#!/bin/bash
.
.
your stuff
.
.
end_time==$(date)
echo "program1 ended at $end_time" > program1_log

Otra opción sería crear un archivo vacío para marcar el final del proceso.

#!/bin/bash
.
.
your stuff
.
.
echo $? > /some/path/program1_ended #storing the exit value
#disadvantage is that you can't verify if intermediate commands failed.

Entonces para comprobarlo

   if [ -e /some/path/program1_ended ]
   then
   exit_status=$( </some/path/program1_ended )
   rm /some/path/program1_ended #Deleting the file, getting ready for next run
   .
   .
   Do something
   else
   echo "program1 has not ended yet"
  fi

Respuesta3

POSIX sh no es muy bueno para manejar múltiples procesos en segundo plano. La herramienta básica es la waitincorporada, que se bloquea hasta que sale un proceso en segundo plano. Pero waitsin argumentos espera hastatodolos procesos en segundo plano han salido y devuelve el estado de salida del último proceso que salió; se pierde el estado de salida de los demás subprocesos.

Puede configurar una trampa para SIGCHLD, que es la señal que se genera cuando el hijo de un proceso sale. Esto ejecuta código cada vez que sale un subproceso. Sin embargo, no necesariamente llega a saber qué subproceso salió o cuál es su estado de devolución. Diferentes caparazones se comportan de manera diferente.

ATT ksh93 (¡no mksh o pdksh!) es el único entre los shells comunes que se comporta de manera útil con las trampas SIGCHLD. Se establece $!en el PID del proceso que salió y $?en su estado de retorno.

#!/bin/ksh
trap 'Process $! (${subprocesses[$!]}) exited with status $?' CHLD
typeset -A subprocesses
program1 & subprocesses[$!]='program1'
program2 & subprocesses[$!]='program2'
wait

Si usa otro caparazón, coloque cualquier tratamiento posterior en el subproceso.

#!/bin/sh
{ program1; echo "program1 exited with status $?"; } &
{ program2; echo "program2 exited with status $?"; } &
wait

O utilice un lenguaje más capaz como Perl, Python, Ruby, etc.

Respuesta4

Si sabes en qué orden finalizarán los procesos, aproximadamente, puedes usar wait <pid>esperar a que salga, y el waitcomando heredará el estado de salida del proceso esperado. p.ej

if wait $pid1
then echo "$pid1 was ok"
else echo "$pid1 failed with code $?"
fi

Si no conoce el orden, puede esperar a cualquiera de ellos wait -n $pid1 $pid2 ...y obtener el código de salida de manera similar, pero no sabrá qué proceso finalizó, pero es útil si solo necesita saber si alguno falló.

información relacionada