问题描述
在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
解决方法
没关系。我在代码中发现了两个小故障,一旦修复它们,它似乎就可以正常工作了。有时您只需要离开几分钟即可。