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

4

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

program1 & program2 & program3 &

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

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

Mas agora, e se eu quiser saber se eles terminaram e, em caso afirmativo, que valor eles retornaram? Algo parecido com isto:

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

Qualquer ajuda será apreciada

    
por Jytug 05.06.2016 / 11:21

4 respostas

3

# 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, você pode, é claro, fazer um loop para aguardar em cada pid e coletar o código de retorno correspondente. Você sai desse loop quando o último filho termina.

    
por 05.06.2016 / 15:21
1

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

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

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

Outra alma seria criar um arquivo vazio para marcar o final 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.

Em seguida, verifique se

   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
    
por 05.06.2016 / 11:27
0

Se você souber em qual ordem os processos terminarão, aproximadamente, você poderá usar wait <pid> para aguardar a saída, e o comando wait herdará o status de saída do processo aguardado. eg

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

Se você não souber o pedido, pode esperar por qualquer um deles com wait -n $pid1 $pid2 ... e obter o código de saída da mesma forma, mas não saberá qual processo foi terminado, mas é útil se você só precisa saber se houver alguma falha.

    
por 05.06.2016 / 15:12
0

POSIX sh não é muito bom em lidar com vários processos em segundo plano. A ferramenta básica é o wait builtin, que bloqueia até que um processo de segundo plano saia. Mas wait sem argumento aguarda até que todos processos em segundo plano tenham saído e retorne o status de saída do último processo que saiu; o status de saída dos outros subprocessos é perdido.

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

ATT ksh93 (não mksh ou pdksh!) é o único entre os shells comuns que se comportam utilmente com os traps SIGCHLD. Ele define $! para o PID do processo que saiu e $? para o 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 outro shell, 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.

    
por 06.06.2016 / 00:04