Comment attendre à bash plusieurs sous-processus pour terminer et retourner le code de sortie!=0 quand un sous-processus se termine par un code!=0?

comment attendre dans un script bash plusieurs sous-processus générés à 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 ?

script Simple:

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

le script ci-dessus attendra tous les 10 sous-processus générés, mais il donnera toujours l'état de sortie 0 (voir help wait ). Comment puis-je modifier ce script pour qu'il découvre les états de sortie des sous-processus frayés et le code de sortie de retour 1 quand tous les sous-processus se terminent par un code !=0?

y a-t-il une meilleure solution que de collecter les pid des sous-processus, de les attendre dans l'ordre et de faire la somme des états de sortie?

430
demandé sur codeforester 2008-12-10 16:54:26

27 réponses

wait aussi (optionnellement) prend le PID du processus pour 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 généré dans un tableau, puis boucle de nouveau en attente sur chaque PID.

# run processes and store pids in array
for i in $n_procs; do
    ./procs[${i}] &
    pids[${i}]=$!
done

# wait for all pids
for pid in ${pids[*]}; do
    wait $pid
done
382
répondu Luca Tettamanti 2018-06-25 10:36:50

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
259
répondu HoverHell 2009-02-05 09:36:30

si vous avez GNU Parallel installé, vous pouvez faire:

# If doCalculations is a function
export -f doCalculations
seq 0 9 | parallel doCalculations {}

GNU Parallel vous donnera le code de sortie:

  • 0 - Tous les travaux se sont déroulés sans erreur.

  • 1-253 - certains emplois ont échoué. Le statut de sortie donne le nombre d'emplois manqués

  • 254 - plus de 253 emplois ont échoué.

  • 255-autre erreur.

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

45
répondu Ole Tange 2018-02-17 17:57:44

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 n'aurait 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
38
répondu Mark Edgar 2009-06-26 10:29:48

Que diriez-vous simplement:

#!/bin/bash

pids=""

for i in `seq 0 9`; do
   doCalculations $i &
   pids="$pids $!"
done

wait $pids

...code continued here ...

mise à jour:

comme l'ont souligné plusieurs commentateurs, ce qui précède attend que tous les processus soient terminés avant de continuer, mais ne se termine pas et échoue si l'un d'eux échoue, il peut être fait à faire avec la modification suivante suggéré par @Bryan, @SamBrightman, et d'autres:

#!/bin/bash

pids=""
RESULT=0


for i in `seq 0 9`; do
   doCalculations $i &
   pids="$pids $!"
done

for pid in $pids; do
    wait $pid || let "RESULT=1"
done

if [ "$RESULT" == "1" ];
    then
       exit 1
fi

...code continued here ...
33
répondu patapouf_ai 2016-09-30 14:38:38

voici un exemple simple en utilisant wait .

exécuter certains processus:

$ sleep 10 &
$ sleep 10 &
$ sleep 20 &
$ sleep 20 &

puis attendez-les avec wait commande:

$ wait < <(jobs -p)

ou tout simplement wait (sans arguments) pour tous.

cela attendra que tous les travaux en arrière-plan soient terminés.

si l'option -n est fournie, attend pour le prochain emploi à terminer et renvoie son statut de sortie.

voir help wait et help jobs pour la syntaxe.

cependant l'inconvénient est que cela retournera seulement sur le statut de la dernière ID, donc vous devez vérifier le statut de chaque sous-processus et le stocker dans la variable.

ou faites votre fonction de calcul pour créer un fichier en cas d'échec (vide ou avec journal d'échec), puis vérifiez ce fichier s'il existe, par exemple

$ sleep 20 && true || tee fail &
$ sleep 20 && false || tee fail &
$ wait < <(jobs -p)
$ test -f fail && echo Calculation failed.
22
répondu kenorb 2016-03-31 14:09:21

pour mettre ça en parallèle...

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

traduisez ça...

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, il ne va pas interrompre les autres processus, mais il en résultera un code de sortie non-zéro 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 définir --max-procs en fonction de la quantité de parallélisme que vous voulez ( 0 signifie"tout à la fois").
  • GNU Parallel offre quelques fonctionnalités supplémentaires lorsqu'il est utilisé à la place de xargs -- mais il n'est pas toujours installé par défaut.
  • la boucle for n'est pas strictement nécessaire dans cet exemple puisque echo $i est essentiellement simplement la régénération de la sortie de $(whatever_list ). Je pense juste que l'utilisation de le mot-clé for rend un peu plus facile de voir ce qui se passe.
  • la manipulation des chaînes de Bash peut être déroutante -- j'ai trouvé que l'utilisation de guillemets simples fonctionne mieux pour envelopper des scripts non-triviaux.
  • vous pouvez facilement interrompre toute l'opération (en utilisant ^C ou similaire), contrairement à l'approche plus directe du parallélisme de Bash .

voici un exemple de travail simplifié...

for i in {0..5} ; do echo $i ; done |xargs -I{} --max-procs 2 bash -c '
   {
   echo sleep {}
   sleep 2s
   }'
17
répondu nobar 2017-05-23 12:02:49

je vois beaucoup de bons exemples énumérés ici, a voulu jeter le mien aussi bien.

#! /bin/bash

items="1 2 3 4 5 6"
pids=""

for item in $items; do
    sleep $item &
    pids+="$! "
done

for pid in $pids; do
    wait $pid
    if [ $? -eq 0 ]; then
        echo "SUCCESS - Job $pid exited with a status of $?"
    else
        echo "FAILED - Job $pid exited with a status of $?"
    fi
done

j'utilise quelque chose de très similaire à démarrer/arrêter des serveurs/services en parallèle et vérifier chaque État de sortie. Fonctionne très bien pour moi. Espérons que cela aide quelqu'un!

7
répondu Jason Slobotski 2016-02-24 21:35:00

Je ne crois pas que ce soit possible avec la fonctionnalité intégrée de Bash.

Vous peut recevez une notification lorsqu'un enfant quitte:

#!/bin/sh
set -o monitor        # enable script job control
trap 'echo "child died"' CHLD

cependant, il n'y a aucun moyen apparent d'obtenir l'état de sortie de l'enfant dans le manipulateur de signal.

obtenir ce statut d'enfant est habituellement le travail de la wait famille de fonctions dans les APIs de niveau inférieur POSIX. Malheureusement Bash de soutien est limité - vous pouvez attendre un processus enfant spécifique (et obtenir son statut de sortie) ou vous pouvez attendre tous d'entre eux, et toujours obtenir un résultat 0.

ce qu'il semble impossible de faire est l'équivalent de waitpid(-1) , qui bloque jusqu'à n'importe quel retours de processus enfant.

6
répondu Alnitak 2008-12-10 14:28:32

le code suivant attendra l'achèvement de tous les calculs et retournera l'état de sortie 1 si l'un des docalculs échoue.

#!/bin/bash
for i in $(seq 0 9); do
   (doCalculations $i >&2 & wait %1; echo $?) &
done | grep -qv 0 && exit 1
5
répondu errr 2011-10-20 17:15:27

stocke simplement les résultats hors du shell, par exemple dans un fichier.

#!/bin/bash
tmp=/tmp/results

: > $tmp  #clean the file

for i in `seq 0 9`; do
  (doCalculations $i; echo $i:$?>>$tmp)&
done      #iterate

wait      #wait until all ready

sort $tmp | grep -v ':0'  #... handle as required
5
répondu estani 2012-03-20 11:42:08

voici ma version qui fonctionne pour plusieurs pid, enregistre les avertissements si l'exécution prend trop de temps, et arrête les sous-processus si l'exécution prend plus de temps qu'une valeur donnée.

function WaitForTaskCompletion {
    local pids="" # pids to wait for, separated by semi-colon
    local soft_max_time="" # If execution takes longer than $soft_max_time seconds, will log a warning, unless $soft_max_time equals 0.
    local hard_max_time="" # If execution takes longer than $hard_max_time seconds, will stop execution, unless $hard_max_time equals 0.
    local caller_name="" # Who called this function
    local exit_on_error="${5:-false}" # Should the function exit program on subprocess errors       

    Logger "${FUNCNAME[0]} called by [$caller_name]."

    local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once 
    local log_ttime=0 # local time instance for comparaison

    local seconds_begin=$SECONDS # Seconds since the beginning of the script
    local exec_time=0 # Seconds since the beginning of this function

    local retval=0 # return value of monitored pid process
    local errorcount=0 # Number of pids that finished with errors

    local pidCount # number of given pids

    IFS=';' read -a pidsArray <<< "$pids"
    pidCount=${#pidsArray[@]}

    while [ ${#pidsArray[@]} -gt 0 ]; do
        newPidsArray=()
        for pid in "${pidsArray[@]}"; do
            if kill -0 $pid > /dev/null 2>&1; then
                newPidsArray+=($pid)
            else
                wait $pid
                result=$?
                if [ $result -ne 0 ]; then
                    errorcount=$((errorcount+1))
                    Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]."
                fi
            fi
        done

        ## Log a standby message every hour
        exec_time=$(($SECONDS - $seconds_begin))
        if [ $((($exec_time + 1) % 3600)) -eq 0 ]; then
            if [ $log_ttime -ne $exec_time ]; then
                log_ttime=$exec_time
                Logger "Current tasks still running with pids [${pidsArray[@]}]."
            fi
        fi

        if [ $exec_time -gt $soft_max_time ]; then
            if [ $soft_alert -eq 0 ] && [ $soft_max_time -ne 0 ]; then
                Logger "Max soft execution time exceeded for task [$caller_name] with pids [${pidsArray[@]}]."
                soft_alert=1
                SendAlert

            fi
            if [ $exec_time -gt $hard_max_time ] && [ $hard_max_time -ne 0 ]; then
                Logger "Max hard execution time exceeded for task [$caller_name] with pids [${pidsArray[@]}]. Stopping task execution."
                kill -SIGTERM $pid
                if [ $? == 0 ]; then
                    Logger "Task stopped successfully"
                else
                    errrorcount=$((errorcount+1))
                fi
            fi
        fi

        pidsArray=("${newPidsArray[@]}")
        sleep 1
    done

    Logger "${FUNCNAME[0]} ended for [$caller_name] using [$pidCount] subprocesses with [$errorcount] errors."
    if [ $exit_on_error == true ] && [ $errorcount -gt 0 ]; then
        Logger "Stopping execution."
        exit 1337
    else
        return $errorcount
    fi
}

# Just a plain stupid logging function to replace with yours
function Logger {
    local value=""

    echo $value
}

exemple, attendre la fin des trois processus, enregistrer un avertissement si l'exécution prend plus de 5 secondes, arrêter tous les processus si l'exécution prend plus de 120 secondes. Ne quittez pas le programme en cas d'échec.

function something {

    sleep 10 &
    pids="$!"
    sleep 12 &
    pids="$pids;$!"
    sleep 9 &
    pids="$pids;$!"

    WaitForTaskCompletion $pids 5 120 ${FUNCNAME[0]} false
}
# Launch the function
someting
5
répondu deajan 2016-09-24 09:44:43

si vous avez bash 4.2 ou plus tard disponible, ce qui suit pourrait vous être utile. Il utilise des tableaux associatifs pour stocker les noms de tâche et leur "code" ainsi que les noms de tâche et leurs pids. J'ai également construit dans une méthode simple de limitation de vitesse qui pourrait devenir pratique si vos tâches consomment beaucoup de temps CPU ou I/O et vous voulez limiter le nombre de tâches concurrentes.

le script lance toutes les tâches dans la première boucle et consomme les résultats dans la seconde.

C'est un peu exagéré pour les cas simples, mais cela permet des choses assez soignées. Par exemple, on peut stocker des messages d'erreur pour chaque tâche dans un autre tableau associatif et les imprimer une fois que tout est réglé.

#! /bin/bash

main () {
    local -A pids=()
    local -A tasks=([task1]="echo 1"
                    [task2]="echo 2"
                    [task3]="echo 3"
                    [task4]="false"
                    [task5]="echo 5"
                    [task6]="false")
    local max_concurrent_tasks=2

    for key in "${!tasks[@]}"; do
        while [ $(jobs 2>&1 | grep -c Running) -ge "$max_concurrent_tasks" ]; do
            sleep 1 # gnu sleep allows floating point here...
        done
        ${tasks[$key]} &
        pids+=(["$key"]="$!")
    done

    errors=0
    for key in "${!tasks[@]}"; do
        pid=${pids[$key]}
        local cur_ret=0
        if [ -z "$pid" ]; then
            echo "No Job ID known for the $key process" # should never happen
            cur_ret=1
        else
            wait $pid
            cur_ret=$?
        fi
        if [ "$cur_ret" -ne 0 ]; then
            errors=$(($errors + 1))
            echo "$key (${tasks[$key]}) failed."
        fi
    done

    return $errors
}

main
4
répondu stefanct 2013-09-06 21:01:22

je viens de modifier un script en arrière-plan et de paralléliser un processus.

j'ai fait quelques expériences (sur Solaris avec bash et ksh) et j'ai découvert que 'wait' affiche l'état de sortie si ce n'est pas zéro , ou une liste de jobs qui renvoie une sortie non nulle quand aucun argument PID n'est fourni. Par exemple:

Bash:

$ sleep 20 && exit 1 &
$ sleep 10 && exit 2 &
$ wait
[1]-  Exit 2                  sleep 20 && exit 2
[2]+  Exit 1                  sleep 10 && exit 1

Ksh:

$ sleep 20 && exit 1 &
$ sleep 10 && exit 2 &
$ wait
[1]+  Done(2)                  sleep 20 && exit 2
[2]+  Done(1)                  sleep 10 && exit 1

cette sortie est écrite à stderr, donc un simple la solution à L'exemple OPs pourrait être:

#!/bin/bash

trap "rm -f /tmp/x.$$" EXIT

for i in `seq 0 9`; do
  doCalculations $i &
done

wait 2> /tmp/x.$$
if [ `wc -l /tmp/x.$$` -gt 0 ] ; then
  exit 1
fi

alors que ceci:

wait 2> >(wc -l)

renverra aussi un compte mais sans le fichier tmp. Cela peut aussi être utilisé de cette façon, par exemple:

wait 2> >(if [ `wc -l` -gt 0 ] ; then echo "ERROR"; fi)

mais ce n'est pas beaucoup plus utile que le fichier IMO tmp. Je n'ai pas pu trouver un moyen utile d'éviter le fichier tmp tout en évitant d'exécuter le "wait" dans une sous-cellule, qui ne fonctionnera pas du tout.

4
répondu Tosh 2014-12-03 13:01:08

j'ai essayé et j'ai combiné toutes les meilleures parties des autres exemples ici. Ce script exécutera la fonction checkpids lorsque n'importe quel" processus de background sort, et affichera l'état de sortie sans recourir au sondage.

#!/bin/bash

set -o monitor

sleep 2 &
sleep 4 && exit 1 &
sleep 6 &

pids=`jobs -p`

checkpids() {
    for pid in $pids; do
        if kill -0 $pid 2>/dev/null; then
            echo $pid is still alive.
        elif wait $pid; then
            echo $pid exited with zero exit status.
        else
            echo $pid exited with non-zero exit status.
        fi
    done
    echo
}

trap checkpids CHLD

wait
3
répondu michaelt 2014-02-13 09:37:12
#!/bin/bash
set -m
for i in `seq 0 9`; do
  doCalculations $i &
done
while fg; do true; done
  • set -m vous permet d'utiliser fg & bg dans un script
  • fg , en plus de mettre le dernier processus au premier plan, a le même statut de sortie que le processus qu'il met en avant
  • while fg cessera de boucler quand un fg sort avec un statut de sortie non nul

malheureusement cela ne traitera pas le cas quand un processus dans l'arrière-plan sort avec un non-nulle. (la boucle ne se terminera pas immédiatement. il attendra que les processus précédents soient terminés.)

3
répondu Jayen 2014-12-10 01:51:41

cela fonctionne, devrait être tout aussi bon sinon meilleur que la réponse de @HoverHell!

#!/usr/bin/env bash

set -m # allow for job control
EXIT_CODE=0;  # exit code of overall script

function foo() {
     echo "CHLD exit code is "
     echo "CHLD pid is "
     echo $(jobs -l)

     for job in `jobs -p`; do
         echo "PID => ${job}"
         wait ${job} ||  echo "At least one test failed with exit code => $?" ; EXIT_CODE=1
     done
}

trap 'foo $? $$' CHLD

DIRN=$(dirname ""151900920"");

commands=(
    "{ echo "foo" && exit 4; }"
    "{ echo "bar" && exit 3; }"
    "{ echo "baz" && exit 5; }"
)

clen=`expr "${#commands[@]}" - 1` # get length of commands - 1

for i in `seq 0 "$clen"`; do
    (echo "${commands[$i]}" | bash) &   # run the command via bash in subshell
    echo "$i ith command has been issued as a background job"
done

# wait for all to finish
wait;

echo "EXIT_CODE => $EXIT_CODE"
exit "$EXIT_CODE"

# end

et bien sûr, j'ai immortalisé ce script, dans un projet NPM qui vous permet d'exécuter des commandes bash en parallèle, utile pour tester:

https://github.com/ORESoftware/generic-subshell

3
répondu Alexander Mills 2017-12-14 23:20:16

trap est votre ami. Vous pouvez piéger sur ERR dans beaucoup de systèmes. Vous pouvez piéger EXIT, ou sur DEBUG pour exécuter un morceau de code après chaque commande.

ceci en plus de tous les signaux standards.

2
répondu Paul Hodges 2015-08-27 14:50:21
set -e
fail () {
    touch .failure
}
expect () {
    wait
    if [ -f .failure ]; then
        rm -f .failure
        exit 1
    fi
}

sleep 2 || fail &
sleep 2 && false || fail &
sleep 2 || fail
expect

le set -e en haut fait s'arrêter votre script en cas d'échec.

expect retournera 1 si une sous-tâche échoue.

2
répondu Yajo 2016-06-24 16:18:02

il y a déjà beaucoup de réponses ici, mais je suis surpris que personne ne semble avoir suggéré l'utilisation de tableaux... Donc voilà ce que j'ai fait - cela pourrait être utile à certains à l'avenir.

n=10 # run 10 jobs
c=0
PIDS=()

while true

    my_function_or_command &
    PID=$!
    echo "Launched job as PID=$PID"
    PIDS+=($PID)

    (( c+=1 ))

    # required to prevent any exit due to error
    # caused by additional commands run which you
    # may add when modifying this example
    true

do

    if (( c < n ))
    then
        continue
    else
        break
    fi
done 


# collect launched jobs

for pid in "${PIDS[@]}"
do
    wait $pid || echo "failed job PID=$pid"
done
2
répondu user3728501 2016-10-28 17:14:07

j'ai utilisé ceci récemment (grâce à Alnitak):

#!/bin/bash
# activate child monitoring
set -o monitor

# locking subprocess
(while true; do sleep 0.001; done) &
pid=$!

# count, and kill when all done
c=0
function kill_on_count() {
    # you could kill on whatever criterion you wish for
    # I just counted to simulate bash's wait with no args
    [ $c -eq 9 ] && kill $pid
    c=$((c+1))
    echo -n '.' # async feedback (but you don't know which one)
}
trap "kill_on_count" CHLD

function save_status() {
    local i=;
    local rc=;
    # do whatever, and here you know which one stopped
    # but remember, you're called from a subshell
    # so vars have their values at fork time
}

# care must be taken not to spawn more than one child per loop
# e.g don't use `seq 0 9` here!
for i in {0..9}; do
    (doCalculations $i; save_status $i $?) &
done

# wait for locking subprocess to be killed
wait $pid
echo

de là on peut facilement extrapoler, et avoir un déclencheur (toucher un fichier, envoyer un signal) et changer les critères de comptage (compter les fichiers touchés, ou autre) pour répondre à ce déclencheur. Ou si vous voulez juste "tout" non zéro rc, juste tuer la serrure de save_status.

1
répondu Lloeki 2013-09-26 10:23:16

j'en avais besoin, mais le processus cible n'était pas un enfant du shell actuel, auquel cas wait $PID ne fonctionne pas. J'ai trouvé l'alternative suivante à la place:

while [ -e /proc/$PID ]; do sleep 0.1 ; done

qui repose sur la présence de procfs , qui peut ne pas être disponible (Mac ne le fournit pas par exemple). Donc pour la portabilité, vous pouvez utiliser ceci à la place:

while ps -p $PID >/dev/null ; do sleep 0.1 ; done
1
répondu troelskn 2013-11-05 11:33:24
Le

captant le signal CHLD peut ne pas fonctionner parce que vous pouvez perdre certains signaux s'ils sont arrivés simultanément.

#!/bin/bash

trap 'rm -f $tmpfile' EXIT

tmpfile=$(mktemp)

doCalculations() {
    echo start job $i...
    sleep $((RANDOM % 5)) 
    echo ...end job $i
    exit $((RANDOM % 10))
}

number_of_jobs=10

for i in $( seq 1 $number_of_jobs )
do
    ( trap "echo job$i : exit value : $? >> $tmpfile" EXIT; doCalculations ) &
done

wait 

i=0
while read res; do
    echo "$res"
    let i++
done < "$tmpfile"

echo $i jobs done !!!
1
répondu mug896 2015-07-02 05:22:14

solution pour attendre plusieurs sous-processus et pour sortir lorsque l'un d'eux sort avec un code de statut non-Zéro est en utilisant 'wait-n'

#!/bin/bash
wait_for_pids()
{
    for (( i = 1; i <= $#; i++ )) do
        wait -n $@
        status=$?
        echo "received status: "$status
        if [ $status -ne 0 ] && [ $status -ne 127 ]; then
            exit 1
        fi
    done
}

sleep_for_10()
{
    sleep 10
    exit 10
}

sleep_for_20()
{
    sleep 20
}

sleep_for_10 &
pid1=$!

sleep_for_20 &
pid2=$!

wait_for_pids $pid2 $pid1

le code de statut '127' s'applique à un procédé non existant, ce qui signifie que l'enfant a pu sortir.

1
répondu user3898515 2018-10-02 12:45:16

il peut y avoir un cas où le processus est terminé avant d'attendre le processus. Si nous déclenchons l'attente pour un processus qui est déjà terminé, il va déclencher une erreur comme pid n'est pas un enfant de cette coquille. Pour éviter de tels cas, la fonction suivante peut être utilisée pour déterminer si le processus est complet ou non:

isProcessComplete(){
PID=
while [ -e /proc/$PID ]
do
    echo "Process: $PID is still running"
    sleep 5
done
echo "Process $PID has finished"
}
0
répondu Anju Prasannan 2018-08-09 06:20:10

je pense que la façon la plus simple d'exécuter des travaux en parallèle et de vérifier le statut est d'utiliser des fichiers temporaires. Il y a déjà quelques réponses similaires (par exemple Nietzche-jou et mug896).

#!/bin/bash
rm -f fail
for i in `seq 0 9`; do
  doCalculations $i || touch fail &
done
wait 
! [ -f fail ]

le code ci-dessus n'est pas sûr. Si vous craignez que le code ci-dessus ne s'exécute en même temps que lui-même, il est préférable d'utiliser un nom de fichier plus unique, comme fail.$$. La dernière ligne est de remplir l'exigence: "retour code de sortie 1 quand l'un des sous-processus se termine par le code !=0?"J'ai ajouté une exigence supplémentaire pour nettoyer. Il aurait peut-être été plus clair de l'écrire ainsi:

#!/bin/bash
trap 'rm -f fail.$$' EXIT
for i in `seq 0 9`; do
  doCalculations $i || touch fail.$$ &
done
wait 
! [ -f fail.$$ ] 

voici un extrait similaire pour recueillir des résultats à partir de plusieurs emplois: je crée un répertoire temporaire, j'enregistre les sorties de toutes les tâches secondaires dans un fichier séparé, et puis je les décharge pour examen. Cela ne correspond pas vraiment à la question - je le jette en bonus:

#!/bin/bash
trap 'rm -fr $WORK' EXIT

WORK=/tmp/$$.work
mkdir -p $WORK
cd $WORK

for i in `seq 0 9`; do
  doCalculations $i >$i.result &
done
wait 
grep $ *  # display the results with filenames and contents
0
répondu Mark 2018-08-16 03:07:55

je pense peut-être faire des calculs; echo"?">>/tmp/acc dans un shell interne est exécuté qui est envoyé à l'arrière-plan, puis l'attente, puis /tmp/acc contiendrait la sortie statuts, un par ligne. Je ne suis pas au courant des conséquences des multiples processus qui s'ajoutent au fichier de l'accumulateur, cependant.

voici un essai de cette suggestion:

Fichier: doCalcualtions

#!/bin/sh

random -e 20
sleep $?
random -e 10

fichier: try

#!/bin/sh

rm /tmp/acc

for i in $( seq 0 20 ) 
do
        ( ./doCalculations "$i"; echo "$?" >>/tmp/acc ) &
done

wait

cat /tmp/acc | fmt
rm /tmp/acc

sortie d'exécution ./ try

5 1 9 6 8 1 2 0 9 6 5 9 6 0 0 4 9 5 5 9 8
-2
répondu Nietzche-jou 2008-12-10 15:20:04