产生多个并行wgets并将结果存储在bash数组中,以便在完成所有wgets时进行漂亮打印


5

我在自己的网站上列出了一个很长的网址列表,列在回车分隔的文本文件中。例如:

  • HTTP:/www.mysite.com/url1.html
  • HTTP:/www.mysite.com/url2.html
  • HTTP:/www.mysite.com/url3.html

我需要生成许多并行wgets来命中每个URL两次,检查并检索特定的头,然后将结果保存在一个数组中,我想在一个漂亮的报告中输出。

我使用以下xargs命令获得了我想要的一部分:

xargs -x -P 20 -n 1 wget --server-response -q -O - --delete-after<./urls.txt 2>&1 | grep Caching

问题是如何运行此命令两次并存储以下内容:

  1. 网址命中
  2. grep对缓存头的第一个结果
  3. grep对缓存头的第二个结果

所以输出应该类似于:

=====================================================
http:/www.mysite.com/url1.html
=====================================================
First Hit: Caching: MISS
Second Hit: Caching: HIT

=====================================================
http:/www.mysite.com/url2.html
=====================================================
First Hit: Caching: MISS
Second Hit: Caching: HIT

等等。

只要标题与URL相关联,URLS出现的顺序就不一定受到关注。

由于URL的数量,我需要并行地并行访问多个URL,否则将花费太长时间。

诀窍是如何获得多个并行wgets并以有意义的方式存储结果。如果有更合理的方法(也许写入日志文件?),我没有结婚使用数组?

任何bash大师对我如何进行有任何建议吗?


您的参赛作品是否真的由回车分隔( \r ),而不是新线( \n )或窗户风格 (\r\n)?这是一个文件 苹果电脑?
terdon

1
您可能想要尝试使用gnu parallel。特别是manpage提到“GNU parallel确保命令的输出与你按顺序运行命令时的输出相同。”
kampu

Answers:


3

给出一个小脚本,在给定单个URL的基础上做正确的事情(基于terdon的代码):

#!/bin/bash

url=$1
echo "=======================================";
echo "$url"
echo "=======================================";
echo -n "First Hit: Caching: ";
wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
if [ $? == 0 ]; then echo HIT; else echo MISS; fi;
echo -n "Second Hit: Caching: ";      
wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
if [ $? == 0 ]; then echo HIT; else echo MISS; fi; echo "";

然后使用GNU Parallel并行运行此脚本(例如,一次500个作业):

cat urls.txt | parallel -j500 my_script

GNU Parallel将确保两个进程的输出永远不会混合 - 这是xargs不提供的保证。

您可以在以下位置找到有关GNU Parallel的更多信息 http://www.gnu.org/s/parallel/

你可以在10秒内安装GNU Parallel:

wget -O - pi.dk/3 | sh 

观看介绍视频 http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1


1
啊,是的,应该想到这一点,+ 1。
terdon

0

一个简单的解决方案是记录每个输出 wget 命令到单独的文件并使用 cat 之后合并它们。


我有22,000个网址。我想我可以创建22,000个文本文件然后尝试合并并删除它们但我必须承认我并不是非常喜欢生成所有I / O.
Brad

22,000个文件在我的书中并不多,但我想它来自领土。 time for i in {1..22000}; do echo "Number $i" > $i; done - 1.7秒删除它们:不到一秒钟。
l0b0

0

我将假设您的文件是换行符,而不是回车分隔,因为您提供的命令将无法使用 \r 分开的文件。

如果你的文件 运用 \r 代替 \n 对于行结尾,将其更改为使用 \n 通过运行:

perl -i -pe 's/\r/\n/g' urls.txt 

如果您使用的是Windows风格( \r\n )行结尾,使用此:

perl -i -pe 's/\r//g' urls.txt 

现在,一旦你的文件是Unix格式, 如果你不介意你的工作没有并行运行 ,你可以做这样的事情:

while read url; do 
  echo "=======================================";
  echo "$url"
  echo "=======================================";
  echo -n "First Hit: Caching: ";
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi;
  echo -n "Second Hit: Caching: ";      
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi; echo "";
done < urls.txt

更新以回应您的评论:

如果您有22,000个URL,我确实可以理解为什么要并行执行此操作。您可以尝试的一件事是创建tmp文件:

(while read url; do 
 ( 
  echo "=======================================";
  echo "$url"
  echo "=======================================";
  echo -n "First Hit: Caching: ";
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi;
  echo -n "Second Hit: Caching: ";      
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi; 
  echo ""; ) > `mktemp urltmpXXX` 2>/dev/null&
done < urls.txt )

那里有两个子炮弹,第一个, (while ... < urls.txt) 只是为了 禁止完成消息 。第二 ( ( echo "=== ... ) > mktemp urltmpXXX )是否将给定URL的所有输出收集到一个文件中。

上面的脚本将创建22,000个tmp文件 urltmpXXX 在哪里 XXX 由随机字符替换。由于tmp文件在完成后都会有6行文本,因此您可以使用以下命令监视(并可选择删除文件):

b=`awk 'END{print NR}' urls.txt`; 
while true; do 
 a=`wc -l urltmp* | grep total | awk '{print $1}'`;     
 if [ $a == $((6 * $b)) ]; then cat urltmp* > urls.out; break; 
  else sleep 1; fi; 
done

现在另一个问题是,这将同时启动22000个工作岗位。根据您的系统,这可能是也可能不是问题。解决这个问题的一种方法是 split 您的输入文件然后为每个文件运行上面的循环一次。


谢谢我已经有一个连续运行的脚本。 I.E.一次一个网址。问题是我们有22,000个网址可供使用。连续运行它们需要太长时间。我需要一个并行执行的解决方案,以减少运行脚本的时间。问题是,一旦你并行执行,你如何以一种可以在之后产生合理报告的方式记录结果?
Brad

@Brad我用一种(可能是荒谬的,错综复杂的)并行运行方式更新了我的答案。
terdon

实际上这让我的服务器瘫痪了。哎呀!我想我需要以某种方式打破它/扼杀它。
Brad

@Brad是的,我确实警告过你:)。尝试将文件拆分为100行块: split -l 100 urls.txt,然后在每个文件上运行循环: for file in x*; do (while read url; do ... ;done < $file); done。这里, <$file 取代 <urls.txt
terdon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.