我正在使用GNU grep
PCRE-P
正则表达式支持来匹配文件中的字符串。输入文件包含包含以下字符串的行:
FOO_1BAR.zoo.2.someString:More-RandomString (string here too): 0.45654343
我想捕获上面一行中的数字2
和数字。0.45654343
我使用了正则表达式
grep -Po ".zoo.\K[\d+](.*):\ (.*)$" file
但这给我带来的结果是
2.someString:More-RandomString (string here too): 0.45654343
我能够从第一个捕获组中获取第一个数字2
,并且还可以匹配行末尾的捕获组。但我无法跳过两个捕获组之间的单词/行。
我确实知道我有一个小组(.*)
正在捕捉中间的这些词。我试图做的是包含另一个\K
来忽略它
grep -Po ".zoo.\K[\d+](.*):\K (.*)$" file
但这只给了我第二个捕获组作为0.556984
.
还有一个非捕获组,其(?:)
语法为
grep -Po ".zoo.\K[\d+](?=.someString:More-RandomString (string here too)):\ (.*)$"
但这没有给我带来什么。我在这里缺少什么?
答案1
grep
的名字出现在g/re/p
ed
命令之后。它的主要目的是打印与正则表达式匹配的行。它的职责不是编辑这些行的内容。你有sed
(流编辑器)或awk
为此。
现在,grep
从 GNU 开始,一些实现grep
添加了一个-o
选项来打印每行的匹配部分(正则表达式匹配的内容,而不是其捕获组的匹配部分)。你已经有了一些grep
类似 GNU 的实现(使用-P
)或者pcregrep
支持 PCRE 的正则表达式。
pcregrep
实际上添加了一个-o<n>
选项来打印捕获组的内容。所以你可以这样做:
pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'
但在这里,明显的标准解决方案是使用sed
:
sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'
或者,如果您想要 perl 正则表达式,请使用 perl:
perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'
使用 GNU grep
,如果您不介意匹配项出现在不同的行上,您可以这样做:
$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file
2
0.45654343
请注意,虽然\K
重置了匹配部分的开始,但这并不意味着您可以摆脱交替重叠的两个部分。
grep -Po '.zoo.(\K\d+|.:\K。)'
不起作用,就像echo foobar | grep -Po 'foo|foob'
不起作用(同时打印foo
和foob
)。foo|foob
首先匹配foo
,然后grep
在 后的输入中查找潜在的其他匹配项foo
,因此从b
of开始bar
,因此之后无法找到更多匹配项。
上面的,我们只在交替的第二部分中grep -Po '\.zoo\.\K\d+|:\s+\K.*'
查找。:<spaces><anything>
这确实匹配后面的部分.zoo.<digits>
,但这也意味着它会:<spaces><anything>
在输入中的任何位置找到那些内容,而不仅仅是当它们跟随时.zoo.<digits>
。
不过,有一种方法可以解决这个问题,即使用另一个 PCRE 特殊运算符:\G
。\G
匹配主题的开头。对于单个匹配,这相当于^
,但对于多个匹配(想想中的sed
/perl
标志),就像 with where尝试查找行中的所有匹配,它也在上一个匹配结束后匹配。所以如果你做到了:g
s/.../.../g
-o
grep
grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
(?!^)
负前瞻运算符在哪里,这意味着不在行的开头,它\G
只会在上一次成功(非空)匹配之后匹配,因此.*:\s+\K.*
只有在上一次成功匹配之后才会匹配,并且只能是这个.foo.<digits>
匹配,因为交替的其他部分匹配到行尾。
在这样的输入上:
.zoo.1.zoo.2 tar: blah
那会输出:
1
2
blah
尽管。如果您不希望这样,您还希望交替的第一部分仅在行的开头匹配。就像是
grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
它仍然在像or 这样的2
输入上输出。您可以在交替的第一部分使用前瞻运算符来解决这个问题,并在后面查找至少一个非空格(也可以用来 避免非字符问题).zoo.2 no colon character
.zoo.2 blah:
:<spaces>
$
grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'
您可能需要几页注释来解释该正则表达式,所以我仍然会选择直接sed
/perl
解决方案......