bash 同时执行多个shell脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8246172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 21:13:58  来源:igfitidea点击:

Execute multiple shell scripts concurrently

bashshellparallel-processing

提问by akry

I want to do the following things:

我想做以下事情:

  • Execute multiple shell scripts (here 2 scripts) concurrently.

  • Wait until both scripts finish

  • Dump return value of each script

  • 同时执行多个 shell 脚本(这里是 2 个脚本)。

  • 等待两个脚本完成

  • 转储每个脚本的返回值

However, main.shdoes not work as expected.

但是,main.sh没有按预期工作。



main.sh

主文件

#!/bin/bash

ret1=`./a.sh` &
ret2=`./b.sh`

if [ "${ret1}"="" -a "${ret2}"="" ]; then
   sleep 1
else
   echo ${ret1},${ret2}
end

a.sh

#!/bin/bash
sleep 10
echo 1

b.sh

b.sh

#!/bin/bash
sleep 5
echo 2

回答by Ole Tange

If you have GNU Parallel http://www.gnu.org/software/parallel/installed you can do this:

如果你安装了 GNU Parallel http://www.gnu.org/software/parallel/你可以这样做:

parallel -j0 '{}; echo $?' ::: a.sh b.sh

I have a suspicion that you want the exit code to check if one of them failed, and that you actually do not care what the precise exit code was. In that case you can do:

我怀疑您希望退出代码检查其中一个是否失败,并且您实际上并不关心确切的退出代码是什么。在这种情况下,你可以这样做:

parallel -j0 ::: a.sh b.sh || echo one or both of them failed

If it is sufficient to get the error code of the last that failed:

如果获取最后失败的错误代码就足够了:

parallel -j0 --halt 1 ::: a.sh b.sh; echo $?

Maybe you would like to kill a.sh if b.sh finishes early but fails:

如果 b.sh 提前完成但失败,您可能想杀死 a.sh:

parallel -j0 --halt 2 ::: a.sh b.sh; echo $?

You can install GNU Parallel simply by:

您可以简单地通过以下方式安装 GNU Parallel:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

Watch the intro videos for GNU Parallel to learn more: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

观看 GNU Parallel 的介绍视频以了解更多信息:https: //www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Print the cheat sheet: https://www.gnu.org/software/parallel/parallel_cheat.pdf

打印备忘单:https: //www.gnu.org/software/parallel/parallel_cheat.pdf

回答by Lee Netherton

Here is some code that I have been running, that seems to do exactly what you want. Just insert ./a.shand ./b.shwhere appropriate:

这是我一直在运行的一些代码,它似乎完全符合您的要求。只需插入./a.sh./b.sh在适当的地方:

# Start the processes in parallel...
./script1.sh 1>/dev/null 2>&1 &
pid1=$!
./script2.sh 1>/dev/null 2>&1 &
pid2=$!
./script3.sh 1>/dev/null 2>&1 &
pid3=$!
./script4.sh 1>/dev/null 2>&1 &
pid4=$!

# Wait for processes to finish...
echo -ne "Commands sent... "
wait $pid1
err1=$?
wait $pid2
err2=$?
wait $pid3
err3=$?
wait $pid4
err4=$?

# Do something useful with the return codes...
if [ $err1 -eq 0 -a $err2 -eq 0 -a $err3 -eq 0 -a $err4 -eq 0 ]
then
    echo "pass"
else
    echo "fail"
fi

Note that this captures the exit status of the script and not what it outputs to stdout. There is no easy way of capturing the stdoutof a script running in the background, so I would advise you to use the exit statusto return information to the calling process.

请注意,这会捕获脚本的退出状态,而不是它输出到的内容stdout。没有简单的方法可以捕获stdout在后台运行的脚本的状态,因此我建议您使用退出状态将信息返回给调用进程。

回答by Michael Dillon

The answer you seek is in this question shell - get exit code of background process

您寻求的答案在这个问题外壳中 - 获取后台进程的退出代码

Basically, when you background a process you can't get its exit code directly. But if you run the bash wait command, then wait's exit code will return the exit code of the background process.

基本上,当您后台进程时,您无法直接获取其退出代码。但是如果你运行 bash wait 命令,那么wait的退出代码将返回后台进程的退出代码。

./a.sh &
pid1=$!
./b.sh
ret2=$?
wait ${pid1}
ret1=$?

This will work even if a.sh ends before you run wait. The special variable $?holds the exit code of the previous process. And $!holds the Process ID of the previously run process.

即使 a.sh 在您运行等待之前结束,这也将起作用。特殊变量$?保存前一个进程的退出代码。并$!保存之前运行的进程的进程 ID。

回答by stefanct

If you have bash 4.2 or later available the following might be useful to you. It uses associative arrays to store task names and their "code" as well as task names and their pids. I have also built in a simple rate-limiting method which might come handy if your tasks consume a lot of CPU or I/O time and you want to limit the number of concurrent tasks.

如果您有 bash 4.2 或更高版本可用,以下内容可能对您有用。它使用关联数组来存储任务名称及其“代码”以及任务名称及其 pid。我还内置了一个简单的速率限制方法,如果您的任务消耗大量 CPU 或 I/O 时间并且您想限制并发任务的数量,它可能会派上用场。

The script launches all tasks in the first loop and consumes the results in the second one.

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

This is a bit overkill for simple cases but it allows for pretty neat stuff. For example one can store error messages for each task in another associative array and print them after everything has settled down.

对于简单的情况,这有点矫枉过正,但它允许非常整洁的东西。例如,可以将每个任务的错误消息存储在另一个关联数组中,并在一切稳定后打印它们。

(I have copied this answer over from my answer herebecause it solves both questions, if that's not ok please tell me or replace it directly with just a link or whatever is suitable.)

(我已经从我的答案here复制了这个答案,因为它解决了这两个问题,如果这不行,请告诉我或直接用链接或任何合适的东西替换它。)

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

回答by William Pursell

Backticks do not give the value returned by the command, but the output of the command. To get the return values:

反引号不给出命令返回的值,而是命令的输出。获取返回值:

#!/bin/sh

./a.sh &
./b.sh
ret2=$?   # get value returned by b.sh
wait %1   # Wait for a.sh to finish
ret1=$?   # get value returned by a.sh
echo "$ret1: $ret2"

If you mistated the question and do in fact want the output of the commands, you get that as well since they will both go to the stdout of the script.

如果您误解了这个问题并且实际上确实想要命令的输出,那么您也会得到它,因为它们都将转到脚本的标准输出。