如何维护对多个后台进程的监视并根据其返回码做出响应?

问题描述

在bash中,我试图维护一定数量文件下载过程。基本上,我有两个来源之一的文件列表。因此,我的脚本将执行以下操作:

  • 读取正在处理的列表
  • 拉取要获取的完整URL
  • 提取实际的文件名,因为URL又长又丑,并且经常导致文件错误命名。每个列表在URL中都有自己的文件名位置,因此将检查列表名称,并根据源文件名确定URL中文件名的位置。
  • 如果活动下载次数少于10,则开始下载文件
  • 如果活动下载= 10,则请等到其中一个退出
  • RC为0时,开始下载列表中的下一个文件
  • 在非零RC上,报告来自wget的不良RC并中止脚本,从而使任何当前正在运行的wget实例处于运行状态
  • 当列表为空时,要么是因为它启动时少于10个,要么是所有文件都已被提取或已被拉出,请等待其余wget实例干净地完成,然后干净地退出脚本

我的问题是,尽管将wget包装在函数中并用&调用了该函数,但wget并没有进入后台。它会暂停整个脚本,直到完成为止。这不是很好,因为某些URL是经过时间编码的,如果我在一定时间内没有下载它们,则Web服务器会抛出错误而不是我想要的文件。因此,如果要提取30个以上的文件(并非不常见),则等待每个文件完成都不会起作用。

这是脚本。任何帮助是极大的赞赏!忽略doDEBUG的东西。那只是我尝试过的故障排除,它揭示了问题出在哪里,而不是为什么。

#!/bin/bash
# when script is confirmed as working ok. set DEBUG to 0
#set -x # should not be necessary!

DEBUG=1
SET_X=0

doDEBUG() {
    [ $DEBUG -eq 0 ] && return
    if [ $SET_X -eq 0 ] ; then
        echo -n "";
        set -x
        SET_X=1;
    fi
    read -p "Press <ENTER> to Continue..."
}


grabFN() {
    echo `echo $1 | cut -f $FLD -d / | cut -f 1 -d \?`
}

enqueue() { 
    URL=$1 FN=$(grabFN $1)
#   Fetch Limit of 10 processes at once
    doDEBUG
    wget $URL -O $FN -o log.$FN
    doDEBUG
    [ -n $? ] && echo $URL >> $INFILE
}

fetchURL() { 
    THISURL="`head -n 1 $INFILE`"
    [ "$THISURL" = "__EMD__" ] && return 1;
    grep -v "$THISURL" $INFILE > tmp.$INFILE
    mv tmp.$INFILE $INFILE
}

doDEBUG
if [ $1 = "getlst.src1" ] ; then FLD=5; else if [ $1 = "getlst.src2" ]; then FLD=9; else echo "UnkNown file: ${1}! Use kNown files or update the script!"; fi; fi
pids=""
INFILE=$1
doDEBUG
# Run five concurrent processes
for i in {1..10}; do
    fetchURL || break
    doDEBUG
        ( enqueue $THISURL ) &
    doDEBUG
        # store PID of process
        pids+=" $!"
    doDEBUG
done

# Wait for all processes to finish,will take max 14s
# as it waits in order of launch,not order of finishing
for p in $pids; do
        if wait $p; then
        NP=""
        for X in $pids do [ $X -eq $p ] || NP+=" $X"; 
        pids=$NP
        doDEBUG
        while [ `echo $pids | wc -l` -lt 10]; do 
            if [ `FETCHURL` ]; then 
                doDEBUG
                ( enqueue $THISURL   ) &
                doDEBUG
                pids+=" $!" ;
            else
                break;
            fi;
        done;
    else
        doDEBUG
        echo "Fetching $THISURL Failed! Aborting Loop!"
        exit 1;
        fi;
done

解决方法

没关系。我在代码中发现了两个小故障,一旦修复它们,它似乎就可以正常工作了。有时您只需要离开几分钟即可。