655 votes

Comment attendre dans bash que plusieurs sous-processus finissent et retournent le code de sortie! = 0 quand un sous-processus se termine avec le code! = 0?

Comment attendre dans un script bash pour plusieurs sous-processus a engendré à partir de ce script pour terminer et retourner le code de sortie !=0 lorsque l'un des sous-processus se termine avec le code !=0 ?

Simple script:

#!/bin/bash
for i in `seq 0 9`; do
  doCalculations $i &
done
wait

Le script ci-dessus va attendre que toutes les 10 engendré sous-processus, mais il sera toujours donner le statut de sortie 0 ( help wait). Comment puis-je modifier ce script donc il va découvrir à la sortie, les statuts de donné naissance les sous-processus et retourner le code de sortie 1 lorsque l'un des sous-processus se termine avec le code !=0?

Est-il une meilleure solution que de collecter les PIDs de la sous-processus, attendre pour eux dans l'ordre et le somme de quitter les statuts?

621voto

Luca Tettamanti Points 2757

wait aussi (facultativement) le PID du processus à attendre, et avec $! vous obtenez le PID de la dernière commande lancée en arrière-plan. Modifiez la boucle pour stocker le PID de chaque sous-processus engendré dans un tableau, puis bouclez à nouveau en attente sur chaque PID.

318voto

HoverHell Points 1140

http://jeremy.zawodny.com/blog/archives/010717.html :

 #!/bin/bash

FAIL=0

echo "starting"

./sleeper 2 0 &
./sleeper 2 1 &
./sleeper 3 0 &
./sleeper 2 0 &

for job in `jobs -p`
do
echo $job
    wait $job || let "FAIL+=1"
done

echo $FAIL

if [ "$FAIL" == "0" ];
then
echo "YAY!"
else
echo "FAIL! ($FAIL)"
fi
 

54voto

Ole Tange Points 700

Si vous avez GNU Parallèle installé, vous pouvez le faire:

seq 0 9 | parallel doCalculations {}

GNU Parallèle vous donnera le code de sortie:

  • 0 - Tous les emplois s'est exécuté sans erreur.

  • 1-253 - Certains emplois échoué. Le statut de sortie donne le nombre de travaux ayant échoué

  • 254 - Plus de 253 emplois échoué.

  • 255 - Autre erreur.

Regarder les vidéos d'intro pour en savoir plus: http://pi.dk/1

10 secondes d'installation:

wget -O - pi.dk/3 | sh

41voto

Mark Edgar Points 1335

Voici ce que j'ai trouvé jusqu'à présent. Je voudrais voir comment interrompre la commande de sommeil si un enfant se termine, de sorte que l'on ne devrait pas accorder WAITALL_DELAY à son usage.

 waitall() { # PID...
  ## Wait for children to exit and indicate whether all exited with 0 status.
  local errors=0
  while :; do
    debug "Processes remaining: $*"
    for pid in "$@"; do
      shift
      if kill -0 "$pid" 2>/dev/null; then
        debug "$pid is still alive."
        set -- "$@" "$pid"
      elif wait "$pid"; then
        debug "$pid exited with zero exit status."
      else
        debug "$pid exited with non-zero exit status."
        ((++errors))
      fi
    done
    (("$#" > 0)) || break
    # TODO: how to interrupt this sleep when a child terminates?
    sleep ${WAITALL_DELAY:-1}
   done
  ((errors == 0))
}

debug() { echo "DEBUG: $*" >&2; }

pids=""
for t in 3 5 4; do 
  sleep "$t" &
  pids="$pids $!"
done
waitall $pids
 

22voto

nobar Points 5849

Pour paralléliser cette...

for i in $(whatever_list) ; do
   do_something $i
done

La traduire de ce...

for i in $(whatever_list) ; do echo $i ; done | ## execute in parallel...
   (
   export -f do_something ## export functions (if needed)
   export PATH ## export any variables that are required
   xargs -I{} --max-procs 0 bash -c ' ## process in batches...
      {
      echo "processing {}" ## optional
      do_something {}
      }' 
   )
  • Si une erreur se produit dans un processus, de ne pas interrompre les autres processus, mais il en résultera un code de sortie non nulle à partir de la séquence dans son ensemble.
  • L'exportation de fonctions et de variables, il peut ou peut ne pas être nécessaire, dans un cas particulier.
  • Vous pouvez configurer --max-procs basé sur la quantité de parallélisme vous voulez (0 signifie "tout à la fois").
  • GNU Parallèle offre quelques fonctionnalités supplémentaires lorsque utilisé à la place de xargs - mais il n'est pas toujours installé par défaut.
  • L' for boucle n'est pas strictement nécessaire dans cet exemple depuis echo $i est fondamentalement juste la régénération de la sortie de l' $(whatever_list). Je pense juste que l'utilisation de l' for mot-clé le rend un peu plus facile de voir ce qui se passe.
  • Bash, la manipulation des chaînes peut être source de confusion -- j'ai trouvé que l'utilisation de guillemets simples qui fonctionne le mieux pour l'emballage non-trivial de scripts.
  • Vous pouvez facilement interrompre l'ensemble de l'opération (à l'aide d' ^C ou similaire), contrairement à l'approche la plus directe pour Bash parallélisme.

Voici une procédure simplifiée de travail exemple...

for i in {0..5} ; do echo $i ; done |xargs -I{} --max-procs 2 bash -c '
   {
   echo sleep {}
   sleep 2s
   }'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X