如何从命令行搜索并打印匹配的相应值?

如何从命令行搜索并打印匹配的相应值?

我有下面的字符串,例如

2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]

我想MATCH使用 查找并打印它的值 10 awk。我可以使用传统方法来做到这一点grepcut但想找到使用sedor 的方法awk

MATCH可以在线上的任意位置。

答案1

sed -n 's/.* MATCH: \([^ ]*\).*/\1/p'

" MATCH: "将打印每个匹配行上最右侧出现的 后的非空格字符序列。

-n告诉sed默认情况下不打印模式空间。如果替换成功,命令p的标志告诉s打印sed模式空间(即替换的结果)。

所以:

sed -n 's/pattern/replacement/p'

是打印成功替换结果的常见习惯用法。

请注意,上面假设输入是有效文本。因为.*匹配任何序列人物,它不会匹配不形成有效字符的字节序列。当以另一种编码处理文本时,这种情况通常发生在 UTF-8 语言环境中。如果您遇到这种情况,您可能需要在上面的行前面加上LC_ALL=C.这使得sed将每个字节视为一个字符,因此不可能存在无效的字节序列。这在这里是可行的,因为我们匹配的字符都来自可移植字符集。

标准awk没有任何等效项,因为它不支持其函数中的捕获组(\(...\)在 中捕获)。\1sub()

在那里,您需要求助于该match()函数:

awk 'match($0, / MATCH: [^ ]*/) {
       print substr($0, RSTART+8, RLENGTH-8)}'

或者使用如下技巧:

awk -F ' MATCH: ' 'NF>1 {sub(/ .*/, "", $2); print $2}'

(请注意,那些人会考虑最左边的发生" MATCH: ")。

GNUawk有一个gensub()函数,其功能与seds命令类似,但有一个设计错误,即它没有告诉您是否进行了任何替换。在这里,你可以这样做:

 gawk '(replacement = gensub(/.* MATCH: ([^ ]*).*/, "\\1", 1)) != $0 {
   print replacement}'

答案2

假设所有行的格式都相同(或至少包含 的所有行MATCH:),则 看起来MATCH:是该行的第 5 个元素,而您想要的值是第 6 个元素。

因此,在 awk 中,您只需测试第 5 个元素是否等于,MATCH:如果正确则打印该行的第 6 个元素。

$ echo "2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]" |awk -e '{ if ($5 == "MATCH:") print $6 }' 
    10

编辑:鉴于假设MATCH:可以位于行中的任何位置:

  $ echo "2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]" |awk -e '{ for (x=1; x<NF; x++ ) { if ($x == "MATCH:") {x=x+1; printf("%s\n", $x); break}}}' 
10

可能不是很优雅,但您需要迭代该行的所有字段并测试每个字段,这是通过循环forif测试完成的。如果测试字段匹配,则打印下一个字段。

我只是添加了一个中断来直接跳转到下一行并继续当前的字段迭代。

在多行文件上:

$ cat terst 
2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]
2017-01-19:31:51 [ABCD:] 37723 - MATCH: 11 [text]
2017-01-19:31:51 [ABCD:] 37723 - [text]
2017-01-19:31:51 37723 - MATCH: 12 [text]
$ awk -e '{ for (x=1; x<NF; x++ ) { if ($x == "MATCH:") {x=x+1; printf("%s\n", $x); break}}}' terst 
10
11
12

相关内容