Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
并行运行bash命令,跟踪结果并计数_Bash - Fatal编程技术网

并行运行bash命令,跟踪结果并计数

并行运行bash命令,跟踪结果并计数,bash,Bash,我想知道,如果可能的话,如何在BASH中创建一个简单的作业管理来并行处理多个命令。也就是说,我有一个要运行的命令的大列表,我希望在任何给定的时间运行其中两个命令 我对bash有相当多的了解,因此以下是使它变得棘手的要求: 这些命令的运行时间是可变的,所以我不能只生成2,等待,然后继续下两个。一个命令完成后,必须立即运行下一个命令 控制进程需要知道每个命令的退出代码,以便它能够保存失败的总数 我想我可以使用trap,但我看不到一种简单的方法来获取处理程序中子级的退出值 那么,关于如何做到这一点

我想知道,如果可能的话,如何在BASH中创建一个简单的作业管理来并行处理多个命令。也就是说,我有一个要运行的命令的大列表,我希望在任何给定的时间运行其中两个命令

我对bash有相当多的了解,因此以下是使它变得棘手的要求:

  • 这些命令的运行时间是可变的,所以我不能只生成2,等待,然后继续下两个。一个命令完成后,必须立即运行下一个命令
  • 控制进程需要知道每个命令的退出代码,以便它能够保存失败的总数
我想我可以使用
trap
,但我看不到一种简单的方法来获取处理程序中子级的退出值

那么,关于如何做到这一点,有什么想法吗


好的,这里有一些概念验证代码可能会工作,但它破坏了bash:生成的命令行无效,挂起,有时是核心转储

# need monitor mode for trap CHLD to work
set -m
# store the PIDs of the children being watched
declare -a child_pids

function child_done
{
    echo "Child $1 result = $2"
}

function check_pid
{
    # check if running
    kill -s 0 $1
    if [ $? == 0 ]; then
        child_pids=("${child_pids[@]}" "$1")
    else
        wait $1
        ret=$?
        child_done $1 $ret
    fi
}

# check by copying pids, clearing list and then checking each, check_pid
# will add back to the list if it is still running
function check_done
{
    to_check=("${child_pids[@]}")
    child_pids=()

    for ((i=0;$i<${#to_check};i++)); do
        check_pid ${to_check[$i]}
    done
}

function run_command
{
    "$@" &
    pid=$!
    # check this pid now (this will add to the child_pids list if still running)
    check_pid $pid
}

# run check on all pids anytime some child exits
trap 'check_done' CHLD

# test
for ((tl=0;tl<10;tl++)); do
    run_command bash -c "echo FAIL; sleep 1; exit 1;"
    run_command bash -c "echo OKAY;"
done

# wait for all children to be done
wait
#陷阱CHLD需要监控模式才能工作
set-m
#存储被监视儿童的PID
声明-一个孩子
函数child_done
{
回显“子项$1结果=$2”
}
功能检查
{
#检查是否正在运行
杀戮-s 0$1
如果[$?==0];则
child_-pids=(“${child_-pids[@]}”“1”)
其他的
等等,1美元
ret=$?
child_完成$1$ret
fi
}
#通过复制pid进行检查,清除列表,然后逐个检查,检查pid
#如果仍在运行,将添加回列表
功能检查完成
{
to_check=(“${child_pids[@]}”)
child_pids=()

对于((i=0;$i我认为以下示例回答了您的一些问题,我正在研究问题的其余部分

(cat list1 list2 list3 | sort | uniq > list123) &
(cat list4 list5 list6 | sort | uniq > list456) &
发件人:


您遇到的问题是无法等待多个后台进程中的一个进程完成。如果您观察作业状态(使用作业),则已完成的后台作业将从作业列表中删除。您需要另一种机制来确定后台作业是否已完成

下面的示例使用启动到后台进程(休眠)。然后使用ps循环以查看它们是否仍在运行。如果没有,则使用wait收集退出代码并启动新的后台进程

#!/bin/bash

sleep 3 &
pid1=$!
sleep 6 &
pid2=$!

while ( true ) do
    running1=`ps -p $pid1 --no-headers | wc -l`
    if [ $running1 == 0 ]
    then
        wait $pid1
        echo process 1 finished with exit code $?
        sleep 3 &
        pid1=$!
    else
        echo process 1 running
    fi

    running2=`ps -p $pid2 --no-headers | wc -l`
    if [ $running2 == 0 ]
    then
        wait $pid2
        echo process 2 finished with exit code $?
        sleep 6 &
        pid2=$!
    else
        echo process 2 running
    fi
    sleep 1
done
编辑:使用SIGCHLD(无轮询):


我可以说服您使用make吗?它的优点是您可以告诉它并行运行多少个命令(修改-j编号)

将它粘贴到一个Makefile中,它将更具可读性

.PHONY: c1 c2 c3 c4
all: c1 c2 c3 c4
c1:
        sleep 2; echo c1
c2:
        sleep 2; echo c2
c3:
        sleep 2; echo c3
c4:
        sleep 2; echo c4
注意,这些不是行开头的空格,它们是选项卡,所以剪切粘贴在这里不起作用

如果命令没有响应,请在每个命令前面加一个“@”。例如:

        @sleep 2; echo c1
这将在第一个失败的命令时停止。如果您需要失败计数,您需要以某种方式在makefile中设计它。可能类似于

command || echo F >> failed
然后检查失败的长度。

为:

$ parallel -j2 < commands.txt
$ echo $?
$parallel-j2

它会将退出状态设置为失败的命令数。如果您有253条以上的命令,请查看
--joblog
。如果您不知道前面的所有命令,请查看
--bg

debian系统还有一个名为xjobs的软件包

您可能想查看它:


如果由于某种原因无法安装
parallel
,这将在普通shell或bash中工作

# String to detect failure in subprocess
FAIL_STR=failed_cmd

result=$(
    (false || echo ${FAIL_STR}1) &
    (true  || echo ${FAIL_STR}2) &
    (false || echo ${FAIL_STR}3)
)
wait

if [[ ${result} == *"$FAIL_STR"* ]]; then
    failure=`echo ${result} | grep -E -o "$FAIL_STR[^[:space:]]+"`
    echo The following commands failed:
    echo "${failure}"
    echo See above output of these commands for details.
    exit 1
fi

其中
true
false
是命令的占位符。您还可以在
FAIL\u STR
中回显$?以获取命令状态。

您可以使用shell的内置“wait”命令获取每个子级并获取其退出状态,但您需要等待特定的pid,否则它将在所有子级返回之前不会返回en已经退出。但是你不想在信号处理程序中等待。这在bash中很棘手,在C中更容易做到。好吧,如果我能在信号处理程序中得到PID,我想我会很好,但我看不到得到PID的方法。我知道用其他语言可以很容易地做到,但我正在尝试对bash脚本进行扩展。可以这样做吗如果我用BASH使用一个处理器,并行运行时的部分值就会丢失。这里的问题是,在您设置
pid1
之前,可以调用ChildFinished。显然,使用
sleep 3
不可以,但一些随机进程可能会很快退出(特别是当它在启动时出错时)使用
(sleep 1&&realcommand)和
如何?在调用ChildFinished之前,这至少需要一秒钟的时间。第二个命令finishing仍然存在竞争,因此可能需要将pid1设置为0(无效)在启动下一个命令之前,在ChildFinished中检查是否已完成。我不喜欢睡眠,但设置为0似乎可以。我将在检查中跳过0,每次启动进程时,在分配变量后再次进行检查(如果已完成)。我将把它封装在几个数组中,看看是否可以让它按我所希望的方式工作。这还假定bash已正确清理,否则,
ps
可能会在僵尸进程中返回1。它通常会返回1,所以我可能会很好。不,这不会满足我的要求。所有命令行都已生成,我需要保留失败和正常的总数。另外,如果其中一个子项失败,我不想停止运行。“command | | echo F>>失败”当它们失败时,将使它们继续。生成命令是什么意思?这与此相符吗?我想我可以从bash脚本生成make文件。我对输出没有太多控制权。此外,我仍然没有一种简单的方法来计算结果(总数和失败数)。我不是说它不起作用,只是这不是一个简单的解决方案。非常感谢您的参考。这个命令看起来很棒。我会看看是否可以修改我的script.FWIW,类似于
xargs-P2-n1-d'\n'sh-c
可以是u吗
$ parallel -j2 < commands.txt
$ echo $?
# String to detect failure in subprocess
FAIL_STR=failed_cmd

result=$(
    (false || echo ${FAIL_STR}1) &
    (true  || echo ${FAIL_STR}2) &
    (false || echo ${FAIL_STR}3)
)
wait

if [[ ${result} == *"$FAIL_STR"* ]]; then
    failure=`echo ${result} | grep -E -o "$FAIL_STR[^[:space:]]+"`
    echo The following commands failed:
    echo "${failure}"
    echo See above output of these commands for details.
    exit 1
fi