我想做以下事情:
同时执行多个shell脚本(此处为2个脚本)。
等到两个脚本完成
转储每个脚本的返回值
但是,main.sh
无效。
#!/bin/bash
ret1=`./a.sh` &
ret2=`./b.sh`
if [ "${ret1}"="" -a "${ret2}"="" ]; then
sleep 1
else
echo ${ret1},${ret2}
end
#!/bin/bash
sleep 10
echo 1
#!/bin/bash
sleep 5
echo 2
答案 0 :(得分:7)
如果你安装了GNU Parallel http://www.gnu.org/software/parallel/,你可以这样做:
parallel -j0 '{}; echo $?' ::: a.sh b.sh
我怀疑您是否希望退出代码检查其中一个是否失败,并且您实际上并不关心精确的退出代码是什么。在这种情况下,你可以这样做:
parallel -j0 ::: a.sh b.sh || echo one or both of them failed
如果足以获得失败的最后一个错误代码:
parallel -j0 --halt 1 ::: a.sh b.sh; echo $?
如果b.sh提前结束但是失败了,也许你想杀死a.sh:
parallel -j0 --halt 2 ::: a.sh b.sh; echo $?
您可以通过以下方式安装GNU Parallel:
wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
观看GNU Parallel的介绍视频了解详情: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
答案 1 :(得分:5)
以下是我一直在运行的一些代码,它们似乎完全符合您的要求。只需在适当的位置插入./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
请注意,这会捕获脚本的退出状态,而不是它输出到stdout
的内容。没有简单的方法来捕获在后台运行的脚本的stdout
,因此我建议您使用exit status将信息返回给调用进程。
答案 2 :(得分:2)
您寻求的答案就是这个问题shell - get exit code of background process
基本上,当您处理后台进程时,无法直接获取其退出代码。但是如果你运行bash wait命令,那么wait
的退出代码将返回后台进程的退出代码。
./a.sh &
pid1=$!
./b.sh
ret2=$?
wait ${pid1}
ret1=$?
即使a.sh在运行等待之前结束,这也会有效。特殊变量$?
保存前一个过程的退出代码。 $!
保存先前运行的进程的进程ID。
答案 3 :(得分:2)
如果您有bash 4.2或更高版本,则以下内容可能对您有用。它使用关联数组来存储任务名称及其“代码”以及任务名称及其pid。我还内置了一个简单的速率限制方法,如果你的任务消耗大量的CPU或I / O时间并且你想要限制并发任务的数量,那么它可能会派上用场。
脚本在第一个循环中启动所有任务,并在第二个循环中使用结果。
对于简单的情况,这有点过分,但它允许非常整洁的东西。例如,可以将每个任务的错误消息存储在另一个关联数组中,并在一切安定下来后打印它们。
(我已经从我的回答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
答案 4 :(得分:0)
反引号不会给出命令返回的值,而是命令的输出。要获得返回值:
#!/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"
如果你误解了这个问题并且确实想要输出命令,那么你也会得到它,因为它们都会转到脚本的标准输出。