código de retorno confiable del process de background

Supongamos la siguiente pieza de código bash:

foo > logfile 2>&1 & foo_pid=$! while ps -p$foo_pid do ping -c 1 localhost done wait $foo_pid if [[ $? == 0 ]] then echo "foo success" fi 

¿Es seguro asumir que $? de hecho, contiene el código de retorno de foo y no el código de retorno de ping ? Si la respuesta a esa pregunta es: "No puedes asumir eso". entonces, ¿cómo puedo modificar este fragment de código para asegurarme de que $? siempre contiene el código de retorno de foo ?

Con bash , tendrás esa garantía a less que hayas comenzado otro trabajo en segundo plano (y ten en count que los trabajos en segundo plano se pueden iniciar con & pero también con coproc y con la sustitución del process) entre el foo & y la wait .

POSIX requiere que un shell recuerde el estado de salida de al less 25 trabajos después de que se hayan ido , pero bash restring mucho más que eso.

Ahora, si lo haces:

 foo & pid=$! ... bar & wait "$pid" 

No hay garantía de que la bar no reciba el mismo pid que foo (si foo ha terminado antes de que comience la bar time), por lo tanto, aunque no sea probable, wait "$pid" para darle el estado de salida de la bar .

Puedes reproducirlo con:

 bash -c '(exit 12; foo) & pid=$! while : bar & [ "$pid" != "$!" ]; do :;done wait "$pid"; echo "$?"' 

que (eventualmente) te dará 0 lugar de 12 .

Para evitar el problema, una manera sería escribirlo como:

 { foo_pid=$! while ps -p "$foo_pid" do ping -c 1 localhost done bar & ... read <&3 ret if [ "$ret" = 0 ]; then echo foo was sucessful. fi } 3< <(foo > logfile 2>&1; echo "$?") 

Sí, puede confiar en wait "$!" para get el estado de un trabajo de background. Cuando se ejecuta como un script, bash no recostack automáticamente trabajos de background completados. Por lo tanto, si ejecuta la wait , reunirá el trabajo en el momento en wait se wait .

Puedes probar esto con un simple script:

 #!/bin/bash sh -c 'sleep 1; exit 22' & sleep 5 echo "FG: $?" wait %1 echo "BG: $?" 

Que dará salida:

 FG: 0 BG: 22 

Creo que su suposition es correcta. Aquí hay un extracto de man bash sobre la espera de processs en segundo plano.

Si n especifica un process o trabajo inexistente, el estado de devolución es 127. De lo contrario, el estado de devolución es el estado de salida del último process o trabajo esperado.

Entonces tal vez deberías verificar 127

Hay una pregunta similar con una respuesta completamente diferente de la que podría ayudar.

Script Bash espere processs y obtenga código de retorno

editar 1

Inspirado por los comentarios y respuestas de @Stephane, amplié su guión. Puedo comenzar unos 34 processs en segundo plano antes de que comience a perder la pista.

tback

 $ cat tback plist=() elist=() slist=([1]=12 [2]=15 [3]=17 [4]=19 [5]=21 [6]=23) count=30 #start background tasksto monitor for i in 1 2 3 4 do #echo pid $i ${plist[$i]} ${slist[$i]} (echo $BASHPID-${slist[$i]} running; exit ${slist[$i]}) & plist[$i]=$! done echo starting $count background echos to test history for i in `eval echo {1..$count}` do echo -n "." & elist[$i]=$! done # wait for each background echo to complete for i in `eval echo {1..$count}` do wait ${elist[$i]} echo -n $? done echo "" # Now wait for each monitonetworking process and check return status with expected failed=0 for i in 1 2 3 4 do wait ${plist[$i]} rv=$? echo " pid ${plist[$i]} returns $rv should be ${slist[$i]}" if [[ $rv != ${slist[$i]} ]] then failed=1 fi done wait echo "Complete $failed" if [[ $failed = "1" ]] then echo Failed else echo Success fi exit $failed $ 

en mi sistema produce

 $ bash tback 14553-12 running 14554-15 running 14555-17 running starting 30 background echos to test history 14556-19 running ..............................000000000000000000000000000000 pid 14553 returns 12 should be 12 pid 14554 returns 15 should be 15 pid 14555 returns 17 should be 17 pid 14556 returns 19 should be 19 Complete 0 Success