Sed:替换字符的 N 次出现

Sed:替换字符的 N 次出现

我希望替换 sed 脚本中每行首次出现 5 次的空白字符。这是我到目前为止所拥有的

sed -e "s/ /;/" -e "s/ /;/" -e "s/ /;/" -e "s/ /;/" -e "s/ /;/" myfile

有更好的方法吗?

顺便说一下,我使用的是 Solaris sed。我不知道这是否有区别。

答案1

阅读你的问题我记得至少 GNU Sed (可能不是你在 Solaris 中拥有的)有您想要的相反功能

g:将替换应用于正则表达式的所有匹配项,而不仅仅是第一个。

number:仅替换正则表达式的第 number 个匹配项。

Note: the posix standard does not specify what should happen when

您混合使用 g 和 number 修饰符,目前 sed 实现中还没有广泛商定的含义。对于 GNU sed,交互定义为:忽略第 3 个之前的匹配,然后匹配并替换第 3 个之后的所有匹配。

所以而不是:

hmontoliu@ulises:/tmp/wb$ echo one two three four five six seven | sed 's/ /;/g5' 
one two three four five;six;seven

您可以通过执行以下操作获得更简洁的命令来实现您想要的目的:

hmontoliu@ulises:/tmp/wb$ echo one two three four five six seven | sed -e 's/ /;/g' -e 's/;/ /6g'
one;two;three;four;five;six seven

请告诉我们 Solaris 实现是否具有该功能。

华泰

答案2

坚持你的基本想法比做一些反复的 sed 杂耍更容易。也许用一个简单的 for 循环来构建模式会让它更容易使用。

pat=; for ((i=1; i<=5; i++)) ;do pat="$pat s/ /;/;"; done
sed -e "$pat" myfile

或者只是放弃多个-e表达式选项,并将它们全部用;表达式分隔符分组。

sed -e "s/ /;/; s/ /;/; s/ /;/; s/ /;/; s/ /;/" myfile

这是 sed-仅有的版本,您通常可能不会打扰,但它确实允许您指定任意数量的替换。 (通过{5})...

sed -nre ':check;G;/^.*\nx{5}$/{b print};s/^(.*)\n.*$/\1/;s/ /;/;t inc-tally;:print;P;x;s/.*//;x;b;:inc-tally;x;s/(.*)/\1x/;x;b check' myfile

以上一行(?)有点可怕,所以这里它是结构化代码,通过 sed 脚本文件调用:sed -nrf "$fsed" myfile

:check             ## check the tally
 G                 ## pattern+=nl+hold
 /^.*\nx{5}$/{     ## we have the full complement of replacements
     b print       ## branch to print (and continue)
 }                 ##      
 s/^(.*)\n.*$/\1/  ##
 s/ /;/            ## change one space (if one is present) 
 t inc-tally       ## branch_on_substitute
:print             ## no more spaces to change
 P                 ## pattern_first_line_print
 x;s/.*//;x        ## kill the accumulated tally chars in hold   
 b                 ## branch to end of proc (continue)
:inc-tally         ##      
 x                 ## swap_pattern_and_hold
 s/(.*)/\1x/       ##
 x                 ## swap_pattern_and_hold
 b check           ## branch_unconditional 

相关内容