2012-03-15 72 views
3

我有以下内容的HTML页面,停止贪婪:如何用grep从庆典

[...] 
<tr><td class="n"><a href="play-1.0.1.zip">play-1.0.1.zip</a></td></tr> 
<tr><td class="n"><a href="play-1.0.2.1.zip">play-1.0.2.1.zip</a></td></tr> 
<tr><td class="n"><a href="play-1.0.2.zip">play-1.0.2.zip</a></td></tr> 
[...] 

而且我想只提取

play-1.0.1.zip 
play-1.0.2.1.zip 
play-1.0.2.zip 

到随后找到最新版本(在这种情况下,将play-1.0.2.1.zip)

所以我试图用

cat tmp.html | grep "<a href=\".*\"" 

<a href="play-1.0.1.zip">play-1.0.1.zip</a></td><td class="m" 
<a href="play-1.0.2.1.zip">play-1.0.2.1.zip</a></td><td class="m" 
<a href="play-1.0.2.zip">play-1.0.2.zip</a></td><td class="m" 

于是,我就懒:

cat tmp.html | grep "<a href=\".*?\"" 

和否定报价

cat tmp.html | grep "<a href=\"[^\"]*?\"" 

他们两个返回没什么

我需要只匹配的部分(而不是href),然后找到最新的,但我stu CK这个贪婪的问题...

-

非常感谢所有的答案,他们都非常有用,这是很难决定哪一个是正确的,到最后我已经解决了它与:

grep -v '.*-RC.*' index.html | grep -oP 'play-1.*?.zip' | sort -Vru | head -1 
+1

的grep -E “ strkol 2012-03-15 13:08:56

+1

有没有必要使用'cat tmp.html'与grep因为grep可以处理它自己的文件。你应该使用'grep -E pattern tmp.html'。 – piotrekkr 2012-03-15 13:17:06

回答

6

相反,其他的答案,这可以完全使用grep完成。

您的输出与您的输入略有不同 - 还有额外的元素显示。对于这个答案的目的,我将使用这个文件:

<tr><td class="n"><a href="play-1.0.1.zip">play-1.0.1.zip</a></td><td class="n"><a href="play-1.0.1.zip">play-1.0.1.zip</a></td></tr> 
<tr><td class="n"><a href="play-1.0.2.1.zip">play-1.0.2.1.zip</a></td><td class="n"><a href="play-1.0.1.zip">play-1.0.1.zip</a></td></tr> 
<tr><td class="n"><a href="play-1.0.2.zip">play-1.0.2.zip</a></td><td class="n"><a href="play-1.0.1.zip">play-1.0.1.zip</a></td></tr> 

有你需要做的几件事情。首先,你需要设置正确的grep开关。您需要:

  • -o只输出每行
  • -P使用Perl兼容的正则表达式引擎

现在你可以使用的匹配部分?改性剂,以防止贪婪匹配:

grep -o -P '<a href=".*?"' test.html 

<a href="play-1.0.1.zip" 
<a href="play-1.0.1.zip" 
<a href="play-1.0.2.1.zip" 
<a href="play-1.0.1.zip" 
<a href="play-1.0.2.zip" 
<a href="play-1.0.1.zip" 

这是不完全正确,因此我们将锚正则表达式来该行的第一场比赛:

grep -o -P '^<tr><td class="n"><a href=".*?"' test.html 

<tr><td class="n"><a href="play-1.0.1.zip" 
<tr><td class="n"><a href="play-1.0.2.1.zip" 
<tr><td class="n"><a href="play-1.0.2.zip" 

这才是正确的,但有太多的克鲁夫特。我们需要使用的是零宽度断言(PCRE语法的一部分)。基本上不包括匹配模式的正则表达式位。

grep -o -P '(?<=^<tr><td class="n"><a href=").*?(?=")' test.html 

play-1.0.1.zip 
play-1.0.2.1.zip 
play-1.0.2.zip 

现在你可以做任何你需要的排序列表。零所宽度断言的更多信息可以在这里找到:http://www.regular-expressions.info/lookaround.html

+0

+1好的答案,以显示你如何迭代到正则表达式。 – 2012-03-15 13:51:08

2

尝试与-E开关:

[email protected]:~$ echo '<a href="play-1.0.1.zip">play-1.0.1.zip</a></td>' | grep -E '<a href=".*?"' 
<a href="play-1.0.1.zip">play-1.0.1.zip</a></td> 
+1

这是有效的,因为默认情况下,grep使用基本的正则表达式引擎。 '-E','-F'和'-P'开关会改变使用的引擎。有关更多详细信息,请参阅手册页。 – 2012-03-15 13:16:40

1

grep似乎不喜欢这样做的正确的工具,因为你要解开一个子匹配。

这里有一个Perl的一行,将做到这一点,但:

$ perl -ne 'while(/<a href="([^"]+)"/g){print $1, "\n";}' input 
play-1.0.1.zip 
play-1.0.2.1.zip 
play-1.0.2.zip 
3
$ grep 'href=' tmp.html | sed 's/.*href="\(.*\)".*/\1/' 
play-1.0.1.zip 
play-1.0.2.1.zip 
play-1.0.2.zip 
+0

好吧......终于有了'sed'解决方案:)...那么这似乎不工作,如果该文件包含其他行,所以在'grep'后面管这个? – 2012-03-15 13:23:11

+0

是的,正确的,修复它,仍然是最短的解决方案呢:-) – strkol 2012-03-15 13:28:37

5

随着GNU工具,你可以做

grep -oP '(?<=<td class="n"><a href=")[^"]+' | sort -Vr | head -1 
0

AWK是一个伟大的工具,如果你知道的场数:

awk -F\" '$4 ~ /play.*zip/{ print $4 }' 

或者这是一种混乱的方式;搜索所有zip文件:

cat file | tr '"' '\n' | grep -e '.zip$' | sort -u 

这将为您获取所有zip文件。 tr实用程序使用不足,它只是替换字符,在这种情况下,用换行符替换每个双引号,很好地在自己的行中获取引用的数据,您可以在其中查找它。排序-u避免了dups。

0

一个Perl方式:

cat thefile | perl -anF'"' -e 'print $F[3],"\n";($v)=$F[3]=~/(\d.*\d)/;$m=$v if$v gt $m;}{print "max=$m\n";' 

输出:

play-1.0.1.zip 
play-1.0.2.1.zip 
play-1.0.2.zip 
max=1.0.2.1 
1

使用克雷格·安德鲁斯通过添加OSX支持提供了答案。

grep -o -P '(?<=^<tr><td class="n"><a href=").*?(?=")' /test.html | sort -n -r -k1.10,12 

结果:

play-1.0.2.1.zip 
play-1.0.2.zip 
play-1.0.1.zip 
+0

就像为那些仅限OS x的用户添加了帮助一样。排序-V在OSX中默认不可用。这也应该适用于其他基于UNIX的机器。 – E1Suave 2012-04-18 19:52:27

3

没看到切割(我喜欢它的简洁&速度),因此:

切-d \” -F4 TMP。 html | sort -Vu | tail -1

输出:

play-1.0.2.1.zip