我有下面的字符串,例如
2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]
我想MATCH
使用 查找并打印它的值 10 awk
。我可以使用传统方法来做到这一点grep
,cut
但想找到使用sed
or 的方法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
没有任何等效项,因为它不支持其函数中的捕获组(\(...\)
在 中捕获)。\1
sub()
在那里,您需要求助于该match()
函数:
awk 'match($0, / MATCH: [^ ]*/) {
print substr($0, RSTART+8, RLENGTH-8)}'
或者使用如下技巧:
awk -F ' MATCH: ' 'NF>1 {sub(/ .*/, "", $2); print $2}'
(请注意,那些人会考虑最左边的发生" MATCH: "
)。
GNUawk
有一个gensub()
函数,其功能与sed
的s
命令类似,但有一个设计错误,即它没有告诉您是否进行了任何替换。在这里,你可以这样做:
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
可能不是很优雅,但您需要迭代该行的所有字段并测试每个字段,这是通过循环for
和if
测试完成的。如果测试字段匹配,则打印下一个字段。
我只是添加了一个中断来直接跳转到下一行并继续当前的字段迭代。
在多行文件上:
$ 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