关于进程:如何在bash中等待多个子进程完成并返回退出代码!= 0当任何子进程以代码结束时!= 0?

How to wait in bash for several subprocesses to finish and return exit code !=0 when any subprocess ends with code !=0?

如何在bash脚本中等待该脚本生成的几个子进程完成并返回退出代码!=0,当任何子进程以代码结束时!= 0?

简单脚本:

1
2
3
4
5
#!/bin/bash
for i in `seq 0 9`; do
  doCalculations $i &
done
wait

上面的脚本将等待所有生成的10个子进程,但它始终给出退出状态0(参见help wait)。如何修改此脚本,以便它在任何子进程以代码结束时发现生成的子进程的退出状态并返回退出代码1!= 0?

有没有比收集子流程的PID、按顺序等待它们并求和退出状态更好的解决方案?


wait还(可选)获取进程的PID等待,并使用$!您将获得在后台启动的最后一个命令的PID。修改循环以将每个生成的子进程的PID存储到一个数组中,然后再次循环等待每个PID。

1
2
3
4
5
6
7
8
9
10
# 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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/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


如果安装了GNU Parallel,可以执行以下操作:

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

GNU Parallel将为您提供退出代码:

  • 0-所有作业运行无错误。

  • 1-253-一些作业失败。退出状态提供失败作业的数量。

  • 254-超过253个作业失败。

  • 255-其他错误。

观看介绍视频了解更多信息:http://pi.dk/1


这是我到目前为止想出来的。我想知道如果一个孩子终止了,如何中断睡眠命令,这样人们就不必调整WAITALL_DELAY来适应自己的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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


简单地说:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

pids=""

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

wait $pids

...code continued here ...

更新:

正如多位评论者所指出的,上述流程在继续之前等待所有流程完成,但如果其中一个流程失败,则不会退出并失败,可以通过@brian、@sambrightman和其他人建议的以下修改来完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/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 ...


下面是使用wait的简单示例。

运行一些进程:

1
2
3
4
$ sleep 10 &
$ sleep 10 &
$ sleep 20 &
$ sleep 20 &

然后用wait命令等待:

1
$ wait < <(jobs -p)

或者只是为了所有人(没有理由)的利益。

这将等待后台的所有作业完成。

如果提供了-n选项,则等待下一个作业终止并返回其退出状态。

语法见:help waithelp jobs

但是,缺点是它只返回最后一个ID的状态,因此您需要检查每个子进程的状态并将其存储在变量中。

或者让您的计算函数在失败时创建一些文件(空的或有失败日志),然后检查该文件是否存在,例如。

1
2
3
4
$ sleep 20 && true || tee fail &
$ sleep 20 && false || tee fail &
$ wait < <(jobs -p)
$ test -f fail && echo Calculation failed.


要将其并行化…

1
2
3
for i in $(whatever_list) ; do
   do_something $i
done

翻译成这个…

1
2
3
4
5
6
7
8
9
10
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(0表示"一次完成")。
  • 当用GNU Parallel代替xargs时,它提供了一些额外的功能——但默认情况下并不总是安装它。
  • 在这个例子中,不需要使用for循环,因为echo $i基本上只是重新生成$(whatever_list的输出。我只是认为使用for关键字可以让您更容易地看到正在发生的事情。
  • bash字符串处理可能会令人困惑——我发现使用单引号最适合包装非琐碎的脚本。
  • 您可以轻松地中断整个操作(使用^C或类似方法),这与更直接的bash并行性方法不同。

下面是一个简单的工作示例…

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


我不相信使用bash的内置功能是可能的。

当子项退出时,您可以收到通知:

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

但是,在信号处理程序中没有明显的方法来获取子进程的退出状态。

在较低级别的POSIX API中,获取子状态通常是wait系列函数的工作。不幸的是,bash对这一点的支持是有限的——您可以等待一个特定的子进程(并获取其退出状态),或者您可以等待所有子进程,并始终获得0结果。

似乎不可能做到的是等效于waitpid(-1),它会阻止任何子进程返回。


我看到这里列出了很多很好的例子,我也想把我的例子也扔进去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#! /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

我使用非常类似的东西来并行启动/停止服务器/服务,并检查每个退出状态。对我来说很好。希望这能帮助别人!


以下代码将等待所有计算完成,如果任何文档计算失败,则返回退出状态1。

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

这是我的版本,适用于多个PID,如果执行时间过长,则记录警告,如果执行时间长于给定值,则停止子流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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秒,则停止所有进程。失败时不要退出程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
function something {

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

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

只需将结果存储在外壳中,例如存储在文件中。

1
2
3
4
5
6
7
8
9
10
11
12
#!/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

如果您有bash 4.2或更高版本,那么下面的内容可能对您有用。它使用关联数组来存储任务名及其"代码",以及任务名及其PID。我还构建了一个简单的速率限制方法,如果您的任务占用大量CPU或I/O时间,并且您想要限制并发任务的数量,那么这个方法可能会很方便。

脚本在第一个循环中启动所有任务,并在第二个循环中使用结果。

对于简单的案例来说,这有点过分,但它允许使用非常整洁的东西。例如,可以将每个任务的错误消息存储在另一个关联数组中,并在所有问题都解决后打印它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#! /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

我刚刚修改了一个脚本到后台,并将一个进程并行。

我做了一些实验(在使用bash和ksh的Solaris上),发现如果"wait"不是零,则输出退出状态,或者在没有提供pid参数时返回非零退出的作业列表。例如。

猛击:

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

Ksh:

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

此输出被写入stderr,因此ops示例的简单解决方案可以是:

1
2
3
4
5
6
7
8
9
10
11
12
#!/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

而这一点:

1
wait 2> >(wc -l)

也将返回一个计数,但不返回tmp文件。也可以这样使用,例如:

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

但是,这并没有比tmp文件imo更有用。我找不到一种有效的方法来避免tmp文件,同时也避免在一个根本不起作用的子shell中运行"wait"。


我已经尝试过了,并结合了这里其他例子中所有最好的部分。此脚本将在任何后台进程退出时执行checkpids函数,并输出退出状态而不进行轮询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/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

这是可行的,如果不是比@hoverhell的答案更好的话,也应该是一个不错的答案!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/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

当然,我已经将这个脚本永久化了,在一个NPM项目中,它允许您并行运行bash命令,这对测试很有用:

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


1
2
3
4
5
6
#!/bin/bash
set -m
for i in `seq 0 9`; do
  doCalculations $i &
done
while fg; do true; done
  • set -m允许您在脚本中使用fg&bg
  • fg除了将最后一个进程置于前台之外,还具有与它所预期的进程相同的退出状态。
  • 当任何一个出口状态为非零时,while fg将停止循环。

不幸的是,当后台进程以非零退出状态退出时,这将无法处理这种情况。(循环不会立即终止。它将等待上一个进程完成。)


陷阱是你的朋友。在许多系统中,您可以捕获错误。您可以陷阱退出,或者在调试时在每个命令之后执行一段代码。

除了所有的标准信号。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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使脚本在失败时停止。

如果任何子作业失败,expect将返回1


这里已经有很多答案了,但我很惊讶似乎没有人建议使用数组…这就是我所做的-这可能对将来的一些人有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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

我需要这个,但目标进程不是当前shell的子进程,在这种情况下,wait $PID不起作用。我确实找到了以下替代方案:

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

这取决于procfs的存在,而procfs可能不可用(例如,mac不提供)。因此,对于可移植性,您可以使用它:

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

我最近用过这个(多亏了阿尼塔克):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/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=$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"非零rc,只需从save_状态取消锁定即可。


捕获chld信号可能不起作用,因为如果它们同时到达,您可能会丢失一些信号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/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 !!!

使用"wait-n"可以等待多个子流程,并在其中任何一个子流程退出时退出(状态代码为非零)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/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

状态代码"127"用于不存在的进程,这意味着子进程可能已退出。


这是我使用的东西:

1
2
#wait for jobs
for job in `jobs -p`; do wait ${job}; done

在等待进程之前,可能存在进程已完成的情况。如果我们触发wait等待一个已经完成的进程,它将触发一个错误,比如pid不是这个shell的子进程。为了避免这种情况,可以使用以下功能来确定流程是否完整:

1
2
3
4
5
6
7
8
9
isProcessComplete(){
PID=$1
while [ -e /proc/$PID ]
do
    echo"Process: $PID is still running"
    sleep 5
done
echo"Process $PID has finished"
}

我认为最直接的并行运行作业和检查状态的方法是使用临时文件。已经有几个类似的答案(例如,Nietzche-Jou和Mug896)。

1
2
3
4
5
6
7
#!/bin/bash
rm -f fail
for i in `seq 0 9`; do
  doCalculations $i || touch fail &
done
wait
! [ -f fail ]

上面的代码不是线程安全的。如果您担心上面的代码将与它本身同时运行,那么最好使用一个更唯一的文件名,如fail。最后一行是要满足这样的要求:"当任何子流程以代码结束时,返回退出代码1!"= 0?"我在那里提出了一个额外的清理要求。这样写可能更清楚:

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

下面是一个从多个作业收集结果的类似片段:我创建一个临时目录,将所有子任务的输出记录在一个单独的文件中,然后将它们转储以供审阅。这与问题不符-我把它作为奖励:

1
2
3
4
5
6
7
8
9
10
11
12
#!/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

我想也许可以运行文档计算;echo"$?">>/tmp/acc在发送到后台的子shell中,然后等待,然后/tmp/acc将包含退出状态,每行一个。不过,我不知道附加到收集器文件的多个进程的任何后果。

下面是这个建议的试用版:

文件:文档

1
2
3
4
5
#!/bin/sh

random -e 20
sleep $?
random -e 10

文件:尝试

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/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

运行输出。/尝试

1
5 1 9 6 8 1 2 0 9 6 5 9 6 0 0 4 9 5 5 9 8