Bash GNU Parallel 帮助

3

这是关于并行软件的内容,同时还有非常丰富的手册

(for x in `cat list` ; do 
       do_something $x
   done) | process_output

被替换为此

 cat list | parallel do_something | process_output

我正在尝试在这上面实现它。

    while [ "$n" -gt 0 ]
        do          
        percentage=${"scale=2;(100-(($n / $end) * 100))"|bc -l}}
    #get url from line specified by n from file done1              
nextUrls=`sed -n "${n}p" < done1`
    echo -ne "${percentage}%  $n / $end urls saved going to line 1. current: $nextUrls\r"
#    function that gets links from the url
    getlinks $nextUrls
#save n
    echo $n > currentLine
    let "n--"
    let "end=`cat done1 |wc -l`"
    done

在阅读GNU Parallel文档时,我发现该程序不支持函数,因此无法在并行处理中使用getlinks。

目前为止,我找到的最佳解决方案是:

seq 30 | parallel -n 4 --colsep '  ' echo {1} {2} {3} {4}

生成输出
1 2 3 4 
5 6 7 8 
9 10 11 12 
13 14 15 16 
17 18 19 20 
21 22 23 24 
25 26 27 28 
29 30 

如果我没理解错的话,上面提到的while循环应该像这样编写:
end=`cat done1 |wc -l`
seq $end -1 1 |  parallel -j+4 -k
#(all exept getlinks function goes here, but idk how? )|
# everytime it finishes do
 getlinks $nextUrls

thx for help in advance


你实际上想要做什么,有什么问题吗? - Paŭlo Ebermann
5个回答

5

看起来您需要的是进度条。请尝试:

cat done1 | parallel --eta wget

如果这不是您想要的,请查看semsemparallel --semaphore的别名,通常与GNU Parallel一起安装):
for i in `ls *.log` ; do
  echo $i
  sem -j+0 gzip $i ";" echo done
done
sem --wait

在您的情况下,它将类似于以下内容:
while [ "$n" -gt 0 ]
    do          
    percentage=${"scale=2;(100-(($n / $end) * 100))"|bc -l}}
    #get url from line specified by n from file done1
    nextUrls=`sed -n "${n}p" < done1`
    echo -ne "${percentage}%  $n / $end urls saved going to line 1. current: $nextUrls\r"
    #    function that gets links from the url
    THE_URL=`getlinks $nextUrls`
    sem -j10 wget $THE_URL
    #save n
    echo $n > currentLine
    let "n--"
    let "end=`cat done1 |wc -l`"
done
sem --wait
echo All done

谢谢,但请看我的下一个回答,了解我确切的需求。 - nkvnkv

1
为什么getlinks需要成为一个函数?将该函数转换为shell脚本(应该基本相同,除了您需要导出环境变量,并且当然不能在没有大量工作的情况下影响外部环境)。
当您尝试并行执行时,当然不能将$n保存到currentline中。所有文件将同时被覆盖。

如果进行排序并删除重复的URL,那么在执行getlinks sort -f done1 ">" done2 uniq done2 ">" done1命令后,我会得到这个结果。 - nkvnkv
唯一的问题是让它并行执行:percentage=${"scale=2;(100-(($n / $end) * 100))"|bc -l}} #从文件done1中获取第n行的url nextUrls=sed -n "${n}p" < done1 echo -ne "${percentage}% $n / $end urls saved going to line 1. current: $nextUrls\r",并在完成后将$nextUrls提供给getlinks。 - nkvnkv
我不在意当我读取n时它是20还是30,因为我同时有10个并行,但如果我已经保存了10个并且最后一行应该是5000,那么问题就出现了。 - nkvnkv

0

目前还不太清楚你的脚本的最终目标是什么。如果你想编写一个并行网络爬虫,你可以将下面的内容用作模板。

#!/bin/bash

# E.g. http://gatt.org.yeslab.org/
URL=$1
# Stay inside the start dir
BASEURL=$(echo $URL | perl -pe 's:#.*::; s:(//.*/)[^/]*:$1:')
URLLIST=$(mktemp urllist.XXXX)
URLLIST2=$(mktemp urllist.XXXX)
SEEN=$(mktemp seen.XXXX)

# Spider to get the URLs
echo $URL >$URLLIST
cp $URLLIST $SEEN

while [ -s $URLLIST ] ; do
  cat $URLLIST |
    parallel lynx -listonly -image_links -dump {} \; wget -qm -l1 -Q1 {} \; echo Spidered: {} \>\&2 |
    perl -ne 's/#.*//; s/\s+\d+.\s(\S+)$/$1/ and do { $seen{$1}++ or print }' |
    grep -F $BASEURL |
    grep -v -x -F -f $SEEN | tee -a $SEEN > $URLLIST2
  mv $URLLIST2 $URLLIST
done

rm -f $URLLIST $URLLIST2 $SEEN

0

我在考虑做出更像这样的东西,如果不是并行或者其他什么,因为并行不支持函数,即http://www.gnu.org/software/parallel/man.html#aliases_and_functions_do_not_work

getlinks(){
if [ -n "$1" ]
then
    lynx -image_links -dump "$1" > src
    grep -i ".jpg" < src > links1
    grep -i "http"  < links1 >links  
    sed -e  's/.*\(http\)/http/g'  < links >> done1
    sort -f done1 > done2
    uniq done2 > done1
    rm -rf links1 links src done2 
fi
}
func(){
 percentage=${"scale=2;(100-(($1 / $end) * 100))"|bc -l}}
        #get url from line specified by n from file done1
        nextUrls=`sed -n "${$1}p" < done1`
        echo -ne "${percentage}%  $n / $end urls saved going to line 1. current: $nextUrls\r"
        #    function that gets links from the url
        getlinks $nextUrls
        #save n
        echo $1 > currentLine
        let "$1--"
        let "end=`cat done1 |wc -l`"
}
while [ "$n" -gt 0 ]
    do          
   sem -j10 func $n
done
sem --wait
echo All done

我的脚本变得非常复杂,我不想使用我不确定能完成的东西来使一个功能失效。 这样,我可以使用完整的互联网流量获取链接,这样做应该需要更少的时间。


如果你将funcgetLinks合并成一个脚本而不是函数,那么上面的代码应该可以通过一些小的修改来实现:显然在getLinks中存在竞争条件,因此你需要确保保存的文件名是唯一的。 - Ole Tange

0

尝试了sem

#!/bin/bash
func (){
echo 1
echo 2
}


for i in `seq 10`
do
sem -j10 func 
done
sem --wait
echo All done

你得到

错误

Can't exec "func": No such file or directory at /usr/share/perl/5.10/IPC/Open3.p
m line 168.
open3: exec of func  failed at /usr/local/bin/sem line 3168  

有没有办法在Bash的管道中执行一个函数? - nkvnkv
semparallel --semaphore 的别名,因此对于函数/别名具有相同的限制。 - Ole Tange

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接