如何使用bash中的grep来阻止贪婪

时间:2012-03-15 13:01:48

标签: regex bash grep

我有一个包含以下内容的html页面:

[...]
<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),然后找到最新的,但我仍然坚持这个贪婪的问题......

-

非常感谢所有答案,它们都非常有用,很难确定哪一个是正确的,最后我用以下方法解决了这个问题:

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

9 个答案:

答案 0 :(得分: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

答案 1 :(得分:5)

使用GNU工具,您可以

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

答案 2 :(得分: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

答案 3 :(得分:3)

没看到剪切(我喜欢它的简洁和速度)所以:

  

cut -d \“ - f4 tmp.html | sort -Vu | tail -1

输出:

  

play-1.0.2.1.zip

答案 4 :(得分:2)

使用-E开关尝试:

piotrekkr@piotrekkr-desktop:~$ 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>

答案 5 :(得分: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

答案 6 :(得分:1)

使用 Craig Andrews 提供的答案并添加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

答案 7 :(得分:0)

如果您知道字段编号,Awk是一个很棒的工具:

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

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

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

这将为您获取所有zip文件。 tr实用程序未得到充分利用,它只是替换了一个字符,在这种情况下用换行符替换每个双引号,很好地在自己的行上获取引用数据,你可以在其中进行grep。排序-u避免了重复。

答案 8 :(得分: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
相关问题