我希望替换 sed 脚本中每行出现的 5 个第一次出现的空白字符。这是我到目前为止所拥有的
sed -e "s/ /;/" -e "s/ /;/" -e "s/ /;/" -e "s/ /;/" -e "s/ /;/" myfile
有没有更好的方法呢?
作为记录,我使用的是 Solaris sed。不知道有没有区别
阅读您的问题我记得至少 GNU Sed(可能不是您在 Solaris 中拥有的那个)具有您想要的相反功能:
g:将替换应用于正则表达式的所有匹配项,而不仅仅是第一个。
number:仅替换正则表达式的第 numberth 个匹配项。
Run Code Online (Sandbox Code Playgroud)Note: the posix standard does not specify what should happen when
您混合使用 g 和 number 修饰符,目前在 sed 实现中没有广泛同意的含义。对于 GNU sed,交互定义为:忽略第 1 个之前的匹配,然后匹配并替换第 1 个之后的所有匹配。
所以而不是:
hmontoliu@ulises:/tmp/wb$ echo one two three four five six seven | sed 's/ /;/g5'
one two three four five;six;seven
Run Code Online (Sandbox Code Playgroud)
你可以得到一个更简洁的命令来实现你想要的:
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
Run Code Online (Sandbox Code Playgroud)
请告诉我们 Solaris 实现是否具有该功能。
HTH
坚持你的基本想法比做一些反复的 sed 杂耍更容易。也许用一个简单的 for 循环来构建模式会让它更容易使用。
pat=; for ((i=1; i<=5; i++)) ;do pat="$pat s/ /;/;"; done
sed -e "$pat" myfile
Run Code Online (Sandbox Code Playgroud)
或者只是放弃多个-e
表达式选项,并将它们全部用;
表达式分隔符分组。
sed -e "s/ /;/; s/ /;/; s/ /;/; s/ /;/; s/ /;/" myfile
Run Code Online (Sandbox Code Playgroud)
这是仅 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
Run Code Online (Sandbox Code Playgroud)
上面的一行(?)有点可怕,所以这里它是结构化代码,通过 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
Run Code Online (Sandbox Code Playgroud)