sed:只打印匹配组

Posted

技术标签:

【中文标题】sed:只打印匹配组【英文标题】:sed: print only matching group 【发布时间】:2013-07-04 21:36:07 【问题描述】:

我想获取最后两个数字(一个整数,一个浮点数;后跟可选的空格)并只打印它们。

例子:

foo bar <foo> bla 1 2 3.4

应该打印:

2 3.4

到目前为止,我有以下内容:

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/replacement/p' 

会给我

foo bar <foo> bla 1 replacement

但是,如果我尝试将其替换为第 1 组,则会打印整行。

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/\1/p' 

如何仅打印与组中正则表达式匹配的行部分?

【问题讨论】:

这个问题要求的不仅仅是打印。具有适当权限的人应修改此问题。 为了避免误报 (int + ...) 和 (int + int) 使用:sed -nr 's/.*([0-9]+[\ \t][0-9]+.[0-9]+[\ \t]*$)/\1/p' 【参考方案1】:

匹配整行,所以在你的正则表达式的开头添加一个.*。这会导致整行替换为组的内容

echo "foo bar <foo> bla 1 2 3.4" |
 sed -n  's/.*\([0-9][0-9]*[\ \t][0-9.]*[ \t]*$\)/\1/p'
2 3.4

【讨论】:

我必须添加 -r 或 `--regexp-extended` 选项,否则我会收到 invalid reference \1 on s' 命令的 RHS ` 错误。 @DanielSokolowski 我认为如果您使用 () 而不是 \(\),则会出现该错误。 如果您要提取的字符串并不总是在行尾,请记住将.* 添加到正则表达式的末尾。 这对我不起作用,因为 .* 是贪婪的,而 sed 没有非贪婪的 .*? @DanielDarabos 只需提一下() 不会在 ubuntu 16.04 中引发错误。所以我认为这个评论已经过时了。【参考方案2】:

grep 是正确的提取工具。

使用您的示例和您的正则表达式:

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4

【讨论】:

非常适合整个团队,尽管sed is needed for individual groups grep -o 不移植到运行 msysgit 但 sed 的系统上。 查看@jozxyqk 链接的问题以获得使用前瞻和后瞻来解决这个问题的答案。 您可以通过管道grep -o 调用从模式中提取组。 ***.com/a/58314379/117471 注意更复杂的正则表达式你需要使用`grep -Eo'【参考方案3】:

对于另一种选择,我会选择 awk!

echo "foo bar <foo> bla 1 2 3.4" | awk ' print $(NF-1), $NF; '

这将在空格上拆分输入(我在这里使用 STDIN,但您的输入很容易成为文件),然后打印出最后一个字段,然后打印出最后一个字段。 $NF 变量保存在空间爆炸后找到的字段数。

这样做的好处是,最后两个字段之前的内容是否发生变化并不重要,只要您只想要最后两个字段,它就会继续工作。

【讨论】:

【参考方案4】:

cut 命令就是针对这种情况而设计的。它将在任何分隔符上“剪切”,然后您可以指定应该输出哪些块。

例如: echo "foo bar &lt;foo&gt; bla 1 2 3.4" | cut -d " " -f 6-7

将导致输出: 2 3.4

-d 设置分隔符

-f 选择要输出的“字段”范围,在这种情况下,它是原始字符串的第 6 到第 7 块。您也可以将范围指定为列表,例如6,7

【讨论】:

要仅打印某些列,请通过管道传送到 awk ' print $2" "$6 ' @nurettin 我认为您的评论可能是针对 awk 答案之一。 我在访问此页面时尝试了 cut 并意识到它的局限性,并决定在 awk 中编写一个更通用的版本,而不是作为评论来提高这篇文章的质量。 是的,我认为这属于涉及 awk 的不同答案。执行您所写的剪切命令是:cut -d " " -f 2,6 啊,我不知道,我以为你只能给出范围。谢谢你。【参考方案5】:

我同意@kent 的观点,即这非常适合grep -o。如果您需要在模式中提取组,可以使用第二个 grep 来完成。

# To extract \1 from /xx([0-9]+)yy/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'xx[0-9]+yy' | grep -Eo '[0-9]+'
123
4

# To extract \1 from /a([0-9]+)b/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'a[0-9]+b' | grep -Eo '[0-9]+'
678
9

当我看到 2 个对 grep/sed/awk 的调用通过管道传输时,我通常会感到畏缩,但这并不总是错误的。虽然我们应该锻炼我们高效做事的技能,但“愚蠢的一致性是小脑袋的妖精”和“真正的艺术家船”。

【讨论】:

就像你添加了-E 标志,允许更复杂的正则表达式

以上是关于sed:只打印匹配组的主要内容,如果未能解决你的问题,请参考以下文章

有sed忽略不匹配的行

sed:具有反向前瞻匹配的嵌套组

不认识匹配组

009day--grep和sed作业及awk作业

sed 命令操作

linux指令 sed指令怎么选择列