Executando vários programas em segundo plano e verificando seu valor de retorno

Executando vários programas em segundo plano e verificando seu valor de retorno

suponha que eu queira executar alguns (digamos, três) programas ao mesmo tempo, como este

program1 & program2 & program3 &

se eu quiser saber deles pid's, acho que a melhor maneira é armazená-los, assim

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

Mas agora, e se eu quiser saber se eles terminaram e se sim, qual o valor que retornaram? Algo assim:

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

Qualquer ajuda será apreciada

Responder1

# 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:" $?

Com vários filhos, é claro que você pode fazer um loop para aguardar cada pid e coletar o código de retorno correspondente. Você sai desse ciclo quando o último filho termina.

Responder2

Uma solução simples é escrever uma mensagem em um arquivo de log

Digamos, para o programa 1, faça algo como:

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

Outra solução seria criar um arquivo vazio para marcar o fim do processo

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

Então para verificar faça

   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

Responder3

POSIX sh não é muito bom para lidar com vários processos em segundo plano. A ferramenta básica é a waitinterna, que bloqueia até que um processo em segundo plano seja encerrado. Mas waitsem nenhum argumento espera atétodosos processos em segundo plano foram encerrados e retorna o status de saída do último processo encerrado; o status de saída dos outros subprocessos é perdido.

Você pode definir uma armadilha para SIGCHLD, que é o sinal gerado quando o filho de um processo é encerrado. Isso executa o código sempre que um subprocesso é encerrado. No entanto, você não necessariamente sabe qual subprocesso foi encerrado ou qual é seu status de retorno. Diferentes shells se comportam de maneira diferente.

ATT ksh93 (não mksh ou pdksh!) é o único entre os shells comuns que se comporta de maneira útil com armadilhas SIGCHLD. Define $!o PID do processo que saiu e $?seu status de retorno.

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

Se você usar outra casca, coloque qualquer pós-tratamento no subprocesso.

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

Ou use uma linguagem mais capaz, como Perl, Python, Ruby, etc.

Responder4

Se você souber em que ordem os processos terminarão, aproximadamente, poderá usar wait <pid>para aguardar a saída, e o waitcomando herdará o status de saída do processo esperado. por exemplo

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

Se você não sabe o pedido, pode esperar por qualquer um deles wait -n $pid1 $pid2 ...e obter o código de saída da mesma forma, mas não saberá qual processo terminou, mas é útil se você precisar apenas saber se algum falhou.

informação relacionada