Как ждать в bash нескольких подпроцессов для завершения и возврата кода завершения! = 0, когда любой подпроцесс заканчивается кодом! = 0?

388

Как подождать в bash script для нескольких подпроцессов, порожденных из этого script, чтобы закончить и вернуть код выхода!= 0, когда какой-либо из подпроцессов заканчивается кодом!= 0?

Простой script:

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

Вышеупомянутый script будет ждать все 10 порожденных подпроцессов, но всегда будет давать статус выхода 0 (см. help wait). Как я могу изменить этот script, чтобы он обнаружил статусы выхода порожденных подпроцессов и возвращал код выхода 1, когда какой-либо из подпроцессов заканчивается кодом!= 0?

Есть ли лучшее решение для этого, чем сбор PID подпроцессов, ожидание их по порядку и суммирование статусов выхода?

  • 1
    Это может быть значительно улучшено, чтобы затронуть wait -n , доступный в современном bash и возвращающий только после завершения первой / следующей команды.
  • 0
    если вы хотите проверить с помощью Bash, попробуйте это: github.com/sstephenson/bats
Показать ещё 3 комментария
Теги:
wait

24 ответа

309
Лучший ответ

wait также (необязательно) принимает PID процесса для ожидания и с $! вы получаете PID последней команды, запущенной в фоновом режиме. Измените цикл, чтобы сохранить PID каждого порожденного подпроцесса в массив, а затем снова зациклиться на каждом PID.

  • 1
    как вы можете зацикливаться на 'wait', когда скрипт блокируется до тех пор, пока этот конкретный процесс не прекратится?
  • 8
    Итак, поскольку вы будете ждать всех процессов, не имеет значения, если, например, вы ожидаете первого, в то время как второе уже завершено (второе все равно будет выбрано на следующей итерации). Это тот же подход, который вы использовали бы в C с wait (2).
Показать ещё 12 комментариев
232

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
  • 95
    jobs -p задает PID подпроцессов, которые находятся в состоянии выполнения. Процесс будет пропущен, если процесс завершится до jobs -p . Поэтому, если какой-либо из подпроцессов завершится до jobs -p , состояние выхода этого процесса будет потеряно.
  • 14
    Ух ты, этот ответ намного лучше, чем самый лучший. : /
Показать ещё 5 комментариев
43

Если у вас установлен GNU Parallel, вы можете сделать:

seq 0 9 | parallel doCalculations {}

GNU Parallel даст вам код выхода:

  • 0 - Все задания выполнялись без ошибок.

  • 1-253 - Не удалось выполнить некоторые из заданий. Статус выхода дает количество неудачных заданий

  • 254 - Сработало более 253 заданий.

  • 255 - Другая ошибка.

Смотрите видеоролики, чтобы узнать больше: http://pi.dk/1

Установка за 10 секунд:

wget -O - pi.dk/3 | sh
  • 1
    Спасибо! Но вы забыли упомянуть проблему «путаницы», в которую я впоследствии попал: unix.stackexchange.com/a/35953
  • 1
    Это выглядит как отличный инструмент, но я не думаю, что вышеперечисленное работает как есть в скрипте Bash, где doCalculations - это функция, определенная в этом же скрипте (хотя ОП не doCalculations этого требования). Когда я пытаюсь, parallel говорит /bin/bash: doCalculations: command not found (она говорит это 10 раз для примера seq 0 9 выше). Смотрите здесь для обхода.
Показать ещё 3 комментария
37

Вот что я придумал до сих пор. Я хотел бы видеть, как прерывать команду sleep, если ребенок завершается, так что не нужно было бы настраивать WAITALL_DELAY на одно использование.

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
  • 0
    Можно было бы пропустить этот WAITALL_DELAY или установить его очень низким, так как внутри цикла не запускаются никакие процессы, я не думаю, что это слишком дорого.
25

Как насчет просто:

#!/bin/bash

pids=""

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

wait $pids

...code continued here ...

Update:

Как указано несколькими комментаторами, вышеупомянутое ожидает завершения всех процессов до продолжения, но не выходит и не сработает, если один из них терпит неудачу, его можно сделать со следующей модификацией, предложенной @Bryan, @SamBrightman, и другие:

#!/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 ...
  • 1
    Согласно man-страницам wait, wait с несколькими PID возвращает только значение, возвращенное последним ожидающим процессом. Таким образом, вам нужен дополнительный цикл и ждать каждого PID отдельно, как это предлагается в принятом ответе (в комментариях).
  • 1
    Поскольку это, кажется, нигде не указано на этой странице, я добавлю, что цикл будет for pid in $pids; do wait $pid; done
Показать ещё 6 комментариев
17

Вот простой пример, используя wait.

Запустите некоторые процессы:

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

Затем дождитесь их командой wait:

$ wait < <(jobs -p)

Или просто wait (без аргументов) для всех.

Это будет ждать завершения всех заданий в фоновом режиме.

Если включена опция -n, она ждет завершения следующего задания и возвращает его статус выхода.

Смотрите: help wait и help jobs для синтаксиса.

Однако недостатком является то, что он вернется только к статусу последнего идентификатора, поэтому вам нужно проверить статус для каждого подпроцесса и сохранить его в переменной.

Или сделайте свою вычислительную функцию для создания некоторого файла при сбое (пустой или с журналом сбоев), затем проверьте его, если существует, например

$ sleep 20 && true || tee fail &
$ sleep 20 && false || tee fail &
$ wait < <(jobs -p)
$ test -f fail && echo Calculation failed.
  • 1
    Это должен быть принятый ответ.
  • 0
    Для новичков в bash в этом примере используются два вычисления: sleep 20 && true и sleep 20 && false - то есть: замените их вашими функциями. Чтобы понять && и || , запустите man bash и введите «/» (поиск), затем «^ * Lists» (регулярное выражение), затем введите: man прокрутит вниз до описания && и ||
Показать ещё 1 комментарий
16

Чтобы распараллелить это...

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

Перевести его на это...

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 {}
      }' 
   )
  • Если в одном процессе произошла ошибка, она не будет прерывать другие процессы, но приведет к ненулевому коду выхода из последовательности в целом.
  • Экспорт функций и переменных может быть или не понадобиться в любом конкретном случае.
  • Вы можете установить --max-procs в зависимости от того, сколько parallelism вы хотите (0 означает "все одновременно" ).
  • GNU Parallel предлагает некоторые дополнительные функции при использовании вместо xargs - но он не всегда устанавливается по умолчанию.
  • В этом примере цикл for не является строго необходимым, так как echo $i в основном просто регенерирует вывод $(whatever_list). Я просто думаю, что использование ключевого слова for позволяет немного легче понять, что происходит.
  • Bash Обработка строк может сбивать с толку - я обнаружил, что использование одинарных кавычек лучше всего подходит для обертывания нетривиальных скриптов.
  • Вы можете легко прервать всю операцию (используя ^ C или аналогичную), в отличие от более прямого подхода к Bash parallelism.

Здесь приведен упрощенный рабочий пример...

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

Я вижу много хороших примеров, приведенных здесь, хотел также выбросить мой.

#! /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

Я использую что-то очень похожее на запуск/остановку серверов/служб параллельно и проверку каждого статуса выхода. Отлично работает для меня. Надеюсь, это поможет кому-то!

  • 0
    Когда я останавливаю это с помощью Ctrl + C, я все еще вижу процессы, запущенные в фоновом режиме.
6

Я не думаю, что это возможно с Bash встроенной функциональностью.

Вы можете получать уведомление, когда ребенок выходит:

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

Однако нет очевидного способа получить статус выхода ребенка в обработчике сигнала.

Получение этого дочернего статуса обычно является заданием семейства функций wait в API-интерфейсах POSIX более низкого уровня. К сожалению, поддержка Bash для этого ограничена - вы можете подождать одного конкретного дочернего процесса (и получить его статус выхода), или вы можете дождаться их всех и всегда получать результат 0.

То, что кажется невозможным, - это эквивалент waitpid(-1), который блокируется до тех пор, пока не вернется любой дочерний процесс.

5

Следующий код будет ждать завершения всех вычислений и возврата статуса выхода 1, если какой-либо из doCalculations не удался.

#!/bin/bash
for i in $(seq 0 9); do
   (doCalculations $i >&2 & wait %1; echo $?) &
done | grep -qv 0 && exit 1
4

Здесь моя версия, которая работает для нескольких pids, записывает предупреждения, если выполнение занимает слишком много времени, и останавливает подпроцессы, если выполнение занимает больше времени, чем заданное значение.

function WaitForTaskCompletion {
    local pids="${1}" # pids to wait for, separated by semi-colon
    local soft_max_time="${2}" # If execution takes longer than $soft_max_time seconds, will log a warning, unless $soft_max_time equals 0.
    local hard_max_time="${3}" # If execution takes longer than $hard_max_time seconds, will stop execution, unless $hard_max_time equals 0.
    local caller_name="${4}" # 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="${1}"

    echo $value
}

Пример: подождите, пока все три процесса закончатся, запишите предупреждение, если выполнение занимает регистратор менее 5 секунд, остановите все процессы, если выполнение занимает более 120 секунд. Не выходите из программы при сбоях.

function something {

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

    WaitForTaskCompletion $pids 5 120 ${FUNCNAME[0]} false
}
# Launch the function
someting
4

Если у вас есть bash 4.2 или более поздняя версия, вам может быть полезно следующее. Он использует ассоциативные массивы для хранения имен задач и их "кода", а также имен задач и их значений. Я также разработал простой метод ограничения скорости, который может пригодиться, если ваши задачи потребляют много времени процессора или ввода-вывода, и вы хотите ограничить количество одновременных задач.

script запускает все задачи в первом цикле и потребляет результаты во втором.

Это немного избыточно для простых случаев, но это позволяет довольно аккуратный материал. Например, можно хранить сообщения об ошибках для каждой задачи в другом ассоциативном массиве и печатать их после того, как все опустилось.

#! /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
3

Я только что модифицировал script для фона и распараллеливал процесс.

Я немного экспериментировал (в Solaris с bash и ksh) и обнаружил, что "wait" выводит статус выхода, если он не равен нулю, или список заданий, возвращающих ненулевой выход, когда аргумент PID не предоставляется, Например.

Bash:

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

КШ:

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

Этот вывод записывается в stderr, поэтому простым решением для примера OP может быть:

#!/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

Пока это:

wait 2> >(wc -l)

также вернет счет, но без файла tmp. Это также можно использовать таким образом, например:

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

Но это не намного полезнее, чем файл IMO tmp. Я не мог найти полезный способ избежать tmp файла, а также избегать запуска "wait" в подоболочке, которая вообще не работает.

3

У меня все получилось, и здесь собраны все лучшие части из других примеров. Этот script будет выполнять функцию checkpids, когда любой фоновый процесс завершается, и выдает статус выхода, не прибегая к опросу.

#!/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
#!/bin/bash
set -m
for i in `seq 0 9`; do
  doCalculations $i &
done
while fg; do true; done
  • set -m позволяет использовать fg и bg в script
  • fg, в дополнение к последнему процессу на переднем плане, имеет тот же статус выхода, что и процесс, который он переднего плана
  • while fg прекратит цикл, когда любой fg завершает работу с ненулевым статусом выхода

к сожалению, это не будет обрабатывать случай, когда процесс в фоновом режиме выходит с ненулевым статусом выхода. (цикл не будет немедленно завершен, он будет ждать завершения предыдущих процессов.)

3

Просто сохраните результаты из оболочки, например. в файле.

#!/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
2

Это работает, должно быть так же хорошо, если не лучше, чем @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 $1"
     echo "CHLD pid is $2"
     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 "$0");

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
  • 0
    trap $? $$ кажется, устанавливает код выхода равным 0 и PID для текущей запущенной оболочки bash, каждый раз для меня
  • 0
    Вы абсолютно уверены в этом? Не уверен, имеет ли это смысл.
Показать ещё 1 комментарий
2

Здесь уже много ответов, но я удивлен, что никто, кажется, не предложил использовать массивы... Итак, вот что я сделал - это может быть полезно для некоторых в будущем.

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
Ловушка

- ваш друг. Вы можете использовать ERR во многих системах. Вы можете заблокировать EXIT или DEBUG, чтобы выполнить кусок кода после каждой команды.

Это в дополнение ко всем стандартным сигналам.

1
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

Верхняя часть set -e заставляет ваш script останавливаться при сбое.

expect вернет 1, если какой-либо подзаголовок не удался.

1

Треппинг сигнала CHLD может не работать, потому что вы можете потерять некоторые сигналы, если они пришли одновременно.

#!/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

Мне это нужно, но целевой процесс не был дочерним элементом текущей оболочки, и в этом случае wait $PID не работает. Вместо этого я нашел следующую альтернативу:

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

Это зависит от наличия procfs, который может быть недоступен (например, Mac не предоставляет его). Поэтому для переносимости вы можете использовать это вместо:

while ps -p $PID >/dev/null ; do sleep 0.1 ; done
1

Я использовал это недавно (спасибо Алнитаку):

#!/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 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=$1;
    local rc=$2;
    # 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

Оттуда можно легко экстраполировать и иметь триггер (прикоснуться к файлу, отправить сигнал) и изменить критерии подсчета (прикоснитесь к файлам или что-то еще), чтобы ответить на этот триггер. Или, если вы просто хотите "any" non zero rc, просто убейте блокировку с save_status.

-2

Я думаю, что, возможно, запустите doCalculations; эхо "$?" → /tmp/acc в подоболочке, которая отправляется на задний план, а затем ждать, тогда /tmp/acc будет содержать статусы выхода, по одному на строку. Однако я не знаю о каких-либо последствиях нескольких процессов, добавляемых к файлу аккумулятора.

Вот пример этого предложения:

Файл: doCalcualtions

#!/bin/sh

random -e 20
sleep $?
random -e 10

Файл: 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

Результат работы. /try

5 1 9 6 8 1 2 0 9 6 5 9 6 0 0 4 9 5 5 9 8
  • 1
    Должны быть проблемы с несколькими приложениями, хотя возвращаемые значения могут быть записаны не по порядку, поэтому вы не знаете, какой процесс вернул что ...
  • 0
    Вы можете просто отправить идентификационную информацию со статусами. Во всяком случае, OP хотел знать только, возвращался ли какой-либо из подпроцессов со статусом ≠ 0, независимо от того, какие именно.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню