207

我想 grep 最短的匹配,模式应该是这样的:

<car ... model=BMW ...>
...
...
...
</car>

... 表示任何字符,输入是多行。

4

7 回答 7

331

You're looking for a non-greedy (or lazy) match. To get a non-greedy match in regular expressions you need to use the modifier ? after the quantifier. For example you can change .* to .*?.

By default grep doesn't support non-greedy modifiers, but you can use grep -P to use the Perl syntax.

于 2010-06-12T04:47:31.717 回答
91

实际上,.*?唯一适用于perl. 我不确定等效的 grep 扩展正则表达式语法是什么。幸运的是,您可以将 perl 语法与 grep 一起使用,这样grep -P会起作用,但与不起作用(它会很贪心)grep -E是一样的。egrep

另见:http ://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html

于 2011-04-25T01:26:43.467 回答
18

我的 grep 在尝试了此线程中的内容后有效:

echo "hi how are you " | grep -shoP ".*? "

只需确保在每一行都附加一个空格

(我的是逐行搜索吐词)

于 2012-09-27T19:02:20.130 回答
16

grep

对于非贪婪匹配,grep您可以使用否定字符类。换句话说,尽量避免使用通配符。

例如,要从页面内容中获取所有指向 jpeg 文件的链接,您可以使用:

grep -o '"[^" ]\+.jpg"'

要处理多行,xargs请先通过管道输入。为了性能,使用ripgrep.

于 2015-05-08T18:53:22.507 回答
6

对不起,我迟到了 9 年,但这可能对 2020 年的观众有用。

所以假设你有一条像"Hello my name is Jello". 现在您要查找以 开头'H'和结尾的单词,'o'中间包含任意数量的字符。我们不想要线条,我们只想要文字。因此,我们可以使用以下表达式:

grep "H[^ ]*o" file

这将返回所有单词。它的工作方式是:它将允许所有字符而不是空格字符,这样我们可以避免在同一行中出现多个单词。

现在您可以用您想要的任何其他字符替换空格字符。假设初始行是"Hello-my-name-is-Jello",那么您可以使用以下表达式获取单词:

grep "H[^-]*o" file
于 2020-03-24T13:12:36.797 回答
3

简短的回答是使用下一个正则表达式:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (?s) - 这使得多行匹配
  • .*? - 以惰性方式多次匹配任何字符(最小匹配)

一个(稍微)更复杂的答案是:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

这将使得在以下文本中匹配 car1 和 car2 成为可能

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) 表示捕获组
  • \1 在此上下文中匹配与最近通过捕获组号 1 匹配的相同文本
于 2013-09-13T19:17:23.533 回答
-1

我知道这有点过时了,但我只是注意到这是可行的。它从我的输出中删除了清理和清理。

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
于 2020-03-09T08:35:38.923 回答