我希望替换 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