Sed 替换第n个正则表达式问题

Sed 替换第n个正则表达式问题,sed,Sed,如果我想从字符串中删除第一个句点及其后面的所有内容,在sed中,我可以执行以下操作: echo 2.6.0.3-8 | sed 's/\..*//' 输出: 2 但是,如果我想删除第二个周期及其背后的所有内容,我认为我应该能够这样做(GNU sed): 然而,结果是: 2.6.0.3-8 从手册中: “数字” 仅替换REGEXP的NUMBERth匹配项 我错过了什么?这是因为这个表达式太贪婪了。第一个匹配使用.6.0.3-8,第二个匹配没有剩余文本 你必须更精确地使用正则表达式 $

如果我想从字符串中删除第一个句点及其后面的所有内容,在
sed
中,我可以执行以下操作:

echo 2.6.0.3-8 | sed 's/\..*//'
输出:

2
但是,如果我想删除第二个周期及其背后的所有内容,我认为我应该能够这样做(GNU sed):

然而,结果是:

2.6.0.3-8   
从手册中:

“数字” 仅替换REGEXP的NUMBERth匹配项


我错过了什么?

这是因为这个表达式太贪婪了。第一个匹配使用
.6.0.3-8
,第二个匹配没有剩余文本

你必须更精确地使用正则表达式

$ sed -E 's/([^.]+(\.[^.]+){3}).*/\1/' <<<"2.6.0.3-8"
2.6.0.3-8
$ sed -E 's/([^.]+(\.[^.]+){2}).*/\1/' <<<"2.6.0.3-8"
2.6.0
$ sed -E 's/([^.]+(\.[^.]+){1}).*/\1/' <<<"2.6.0.3-8"
2.6
$ sed -E 's/([^.]+(\.[^.]+){0}).*/\1/' <<<"2.6.0.3-8"
2

$sed-E的/([^.]+(\[^.]+){3})。*/\1/”这是因为表达式是贪婪的。第一个匹配使用
.6.0.3-8
,第二个匹配没有剩余文本

你必须更精确地使用正则表达式

$ sed -E 's/([^.]+(\.[^.]+){3}).*/\1/' <<<"2.6.0.3-8"
2.6.0.3-8
$ sed -E 's/([^.]+(\.[^.]+){2}).*/\1/' <<<"2.6.0.3-8"
2.6.0
$ sed -E 's/([^.]+(\.[^.]+){1}).*/\1/' <<<"2.6.0.3-8"
2.6
$ sed -E 's/([^.]+(\.[^.]+){0}).*/\1/' <<<"2.6.0.3-8"
2

$sed-E的/([^.]+(\[^.]+){3})。*/\1/”你在那里,只是因为被
*
和贪婪所灼伤。对于您的具体案例,您需要做的就是将
*
替换为
[^.]*

$ echo 2.6.0.3-8 | sed 's/\.[^.]*//2g' 2.6 $ echo 2.6.0.3-8 | sed 's/\.[^.]*//3g' 2.6.0 $ echo 2.6.0.3-8 | sed 's/\.[^.]*//1g' 2 $echo 2.6.0.3-8 | sed's/\..[^.]*//2g' 2.6 $echo 2.6.0.3-8 | sed's/\...[^.]*//3g' 2.6.0 $echo 2.6.0.3-8 | sed's/\...[^.]*//1g' 2.
[^.]
表示所有不是点的字符。

你在那里,只是为了被
*
和贪婪所灼伤。对于您的具体案例,您需要做的就是将
*
替换为
[^.]*

$ echo 2.6.0.3-8 | sed 's/\.[^.]*//2g' 2.6 $ echo 2.6.0.3-8 | sed 's/\.[^.]*//3g' 2.6.0 $ echo 2.6.0.3-8 | sed 's/\.[^.]*//1g' 2 $echo 2.6.0.3-8 | sed's/\..[^.]*//2g' 2.6 $echo 2.6.0.3-8 | sed's/\...[^.]*//3g' 2.6.0 $echo 2.6.0.3-8 | sed's/\...[^.]*//1g' 2.
[^.]
表示所有不是点的字符。

正如@stevesliva和@glennjackman所指出的,这里的问题是正则表达式匹配整行,因此没有第二次匹配

似乎没有一种通用的方法来实现仅使用正则表达式的替换。因此,删除第二个句点及其后面所有内容的通用替代方法是使用
P
d
,例如:

echo 2.6.0.3-8 | sed 's/\./\n/2; P; d'
或便携式:

echo 2.6.0.3-8 | sed -e $'s/\\./\\\n/2' -e P -e d
两种情况下的输出:

2.6

正如@stevesliva和@glennjackman所指出的,这里的问题是正则表达式匹配整行,因此没有第二个匹配

似乎没有一种通用的方法来实现仅使用正则表达式的替换。因此,删除第二个句点及其后面所有内容的通用替代方法是使用
P
d
,例如:

echo 2.6.0.3-8 | sed 's/\./\n/2; P; d'
或便携式:

echo 2.6.0.3-8 | sed -e $'s/\\./\\\n/2' -e P -e d
两种情况下的输出:

2.6


你错过了它的贪婪<代码>*
正在吞噬一切,没有第二个匹配项。您可以使用
[^.]*
来获得比
*
更好的效果,因为您不知道它是贪婪的<代码>*
正在吞噬一切,没有第二个匹配项。您可以使用
[^.]*
来获得比
*
+1更好的效果,我明白了,并且使用
g
它也替换了行的其余部分。注意,这使它成为一个特定于GNU的sed。你知道sed的便携式解决方案吗?我相信格伦的是便携式的
-E
比GNU sed手册页建议的
-r
更具POSIX性,但是
-E
将与GNU sed一起使用。是的,你是对的。但是他没有使用我想要的
s///n
表单。我发现了一种稍微有点粗俗的方法,请看我的回答基于我添加到您的答案中的讨论,这些都不能移植到busybox sed。您无法使用
2\g
修复。。。我找不到一种方法来说服它使用数字和g选项。+1,我看到了,
g
它也替换了行的其余部分。注意,这使它成为一个特定于GNU的sed。你知道sed的便携式解决方案吗?我相信格伦的是便携式的
-E
比GNU sed手册页建议的
-r
更具POSIX性,但是
-E
将与GNU sed一起使用。是的,你是对的。但是他没有使用我想要的
s///n
表单。我发现了一种稍微有点粗俗的方法,请看我的回答基于我添加到您的答案中的讨论,这些都不能移植到busybox sed。您无法使用
2\g
修复。。。我找不到方法说服它使用数字和g选项。忽略我之前的评论,这很好,回答得很好。但是,它没有像我在问题中试图做的那样使用
s///n
表单。请参阅@steve关于如何使用GNU-sed和我的回答,这是一种略显粗糙但可移植的方式忽略我之前的评论,这是一个很好的回答。但是,它没有像我在问题中尝试的那样使用
s///n
表单。现在我明白了,请参阅@steve关于如何使用GNU-sed和我的GNU-sed进行操作的回答。我没有注意到你把注意力集中在一个与
g
结合的数字上,这是一种未定义的行为。也就是说,分号应该是可移植的?我在OSX上看到的BSD-sed用户常见的可移植性问题是,在大括号中必须有最后一个分号。@stevesliva:我也这么认为,但是上面提到的Debian的busybox sed在使用分号分隔时失败了,我想这更像是busybox在将单个带引号的字符串传递给busybox sed之前展开字符串的问题。ie:
$echo's/\./\n/2'| sed-f-
导致
sed:file-line 1:unterminated s'命令
,而
$echo's/\./\\./\\\n/2'| sed-f-
没有语法错误。这基本上是一个外壳扩展问题。除非您允许两次字符串扩展,否则Sed看不到正确的命令字符串。@stevesliva:但是它不起作用,请参见例如:
echo的/\\./\\\\n/2'| Sed-f/dev/stdin infle
,其中infle包含版本string。我意识到我重复了您的问题,并测试了这一点<代码>echo 2.6.0.3-8 | busybox sed's/\./\n/2\;Pd’似乎很好用。我认为额外的反斜杠暗示了扩展,但看起来你并不需要它们。Busybox sed不能容忍2后面的分号。似乎