我在自己的网站上有一个很长的 URL 列表,以回车符分隔的文本文件形式列出。例如:
- http://www.mysite.com/url1.html
- http://www.mysite.com/url2.html
- http://www.mysite.com/url3.html
我需要生成多个并行的 wget 来两次访问每个 URL,检查并检索特定的标头,然后将结果保存在一个数组中,以便输出为一份漂亮的报告。
我使用以下 xargs 命令获得了我想要的部分内容:
xargs -x -P 20 -n 1 wget --server-response -q -O - --delete-after<./urls.txt 2>&1 | grep Caching
问题是如何运行此命令两次并存储以下内容:
- URL 命中
- 针对缓存标头执行 grep 的第一个结果
- 针对缓存标头执行 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 关联,URL 出现的顺序就不一定是个问题。
由于 URL 数量较多,我需要并行访问多个 URL,而不是连续访问,否则会花费太长时间。
诀窍在于如何获取多个并行 wget 并以有意义的方式存储结果。如果有更合乎逻辑的方法(例如写入日志文件?),我不会坚持使用数组。
有没有 bash 专家对我该如何进行有什么建议?
答案1
制作一个小脚本,根据一个 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
答案2
一个简单的解决方案是将每个命令的输出记录wget
到单独的文件中,cat
然后用于合并它们。
答案3
我会假设您的文件是换行符,而不是回车符分隔的,因为您给出的命令不适用于\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
输入文件,然后对每个文件运行一次上述循环。