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 <foo> 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:只打印匹配组的主要内容,如果未能解决你的问题,请参考以下文章