163

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

例子:

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' 

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

4

5 回答 5

170

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

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
于 2013-07-07T11:22:10.627 回答
83

grep是正确的提取工具。

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

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4
于 2013-07-07T11:38:52.800 回答
13

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

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

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

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

于 2013-07-07T11:51:56.737 回答
7

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

例如: echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

将导致输出: 2 3.4

-d 设置分隔符

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

于 2017-10-18T00:25:34.780 回答
6

我同意@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 的调用通过管道传输时,我通常会感到畏缩,但这并不总是错误的。虽然我们应该锻炼我们高效做事的技能,但“愚蠢的一致性是小脑袋的妖精”和“真正的艺术家船”。

于 2019-10-10T01:52:04.340 回答