在这种情况下,使用SED(与sed -r 's/[^[:space:]]*/TEST/4g'
相反)可以更改字符串的前4(或更多)次出现:
TEST TEST TEST TEST five six seven
我使用AWK两次按顺序处理单词反转顺序,但这很长很复杂,我只想用SED就能做到这一点:
echo one two three four five six seven | awk '{for(i=NF;i>=1;i--) printf "%s ", $i;print ""}' | sed -r 's/[^ ]*/TEST/4g' | awk '{for(i=NF;i>=1;i--) printf "%s ", $i;print ""}'
也许还有选择更改发生范围的选项,例如3-5、6-12,...?
示例输入为:
一二三四五五六七
八点九十一点十一十二十三点十三十四点
十五十六十七十七十八十九二十一十二
答案 0 :(得分:3)
单个 AWK :
awk '{for(i=1;i<=NF;i++) if(i<5){$i="TEST"}; print}'
试运行:
$ echo one two three four five six seven | awk '{for(i=1;i<=NF;i++) if(i<5){$i="TEST"}; print}'
TEST TEST TEST TEST five six seven
此解决方案简短,可读且可维护。如果您不满意,请添加一些有关您的特定问题的详细信息。
Perl 等效解决方案:
perl -pe 's/\S+/$i++<4?"TEST":$&/ge'
试运行:
$ echo one two three four five six seven | perl -pe 's/\S+/$i++<4?"TEST":$&/ge'
TEST TEST TEST TEST five six seven
也许可以选择更改发生范围,例如3-5、6-12
AWK:
awk '{for(i=3;i<6;i++)$i="TEST";print}'
在新提供的输入文件上运行测试:
$ awk '{for(i=3;i<6;i++)$i="TEST";print}' input
one two TEST TEST TEST six seven
eight nine TEST TEST TEST thirteen fourteen
fifteen sixteen TEST TEST TEST twenty twenty-one
Perl:
perl -pe 's/\S+/++$c~~[3..5]?"TEST":$&/ge'
在新提供的输入文件上运行测试:
$ perl -pe '$c=0;s/\S+/++$c~~[3..5]?"TEST":$&/ge' input
Smartmatch is experimental at -e line 1. <== This is a warning that goes to STDERR
one two TEST TEST TEST six seven
eight nine TEST TEST TEST thirteen fourteen
fifteen sixteen TEST TEST TEST twenty twenty-one
答案 1 :(得分:1)
here由mikeserv提供了答案。 注意:如果要处理一个范围,则需要使用最大范围,因为它会处理尽可能多的匹配项而不会引发任何异常/错误。
GNU sed:
echo 'one two three four five six seven' | \
sed 's/[^[:space:]]*/\n&/g;:t;/\n/{x;/.\{4\}/!{s/$/./;x;s/\n[^[:space:]]*/TEST/;bt};x};s/\n//g'
POSIX sed:
nl='
';
echo 'one two three four five six seven' | sed "s/[^[:space:]]*/\\$nl&/g;:t${nl}/\n/{x;/.\{4\}/!{${nl}s/$/./;x;s/\n[^[:space:]]*/TEST/;bt$nl};x$nl};s/\n//g"
请参见online sed
demo。
原始说明(请注意,1
替换为2
,您可以使用任何其他模式):
我在这里使用了两种著名的技术。首先,每个
1
在行中出现\n1
。这样,就像我 接下来执行递归替换,我可以确定不替换 两次出现 if 我的替换字符串包含我的替换 串。例如,如果我将he
替换为hey
,它将仍然有效。我这样做:
s/1/\ &/g
其次,我通过将一个字符添加到 每次出现
。h
个旧空间。一旦达到三个,就不会再发生了。如果 您将其应用于数据并将\{3\}
更改为总计 您想要的替代品,/\n1/
可以满足您的要求 要替换,您应该只替换任意数量的
答案 2 :(得分:0)
这对于sed来说是完全不合适的任务,因为sed就是对单个字符串仅此做简单的s/old/new/
。在每个UNIX框上的任何外壳中都有任何awk:
$ echo one two three four five six seven | awk '{for (i=1; i<=4; i++) $i="TEST"}1'
TEST TEST TEST TEST five six seven
$ echo one two three four five six seven | awk '{for (i=3; i<=5; i++) $i="TEST"}1'
one two TEST TEST TEST six seven
,如果需要对其进行参数化:
echo one two three four five six seven |
awk -v beg=3 -v end=5 '{for (i=beg; i<=end; i++) $i="TEST"}1'
one two TEST TEST TEST six seven
答案 3 :(得分:0)
$ echo "one two three four fix six" | \
sed -E ':r s/(^|(TEST )+)[^ ]*/\1TEST/;/^(TEST ){4}/!br'
TEST TEST TEST TEST fix six
说明:
:r
标签为r的分支回到s/(^|(TEST )+)[^ ]*/\1TEST/;
替换项,用于替换只出现一个非TEST单词,以行的开头或1个或多个TEST开头/^(TEST ){4}/!br'
正则表达式查找所需内容,然后在!br
尚未匹配的情况下分支回到:r
。显然,这很脆弱。如果任何行没有四个单词,它将无限循环。只能是GNU sed。