sed 或 awk:仅替换第 n 次出现的字符串

sed 或 awk:仅替换第 n 次出现的字符串

如何编写 a sed(或awk,或两者),它将采用以下内容:

echo '1 aa 2 2 3 bb 5 bb 2 5' | sed/awk ...

并且只替换第n次出现的字符串?例如,第三次出现2或第二次出现bb?

因此,预期的输出将是(例如,当替换第二次出现的 时)bbreplaced

1 aa 2 2 3 bb 5 replaced 2 5

输入字符串、替换字符串,n可以是任意输入。

答案1

用于sed更改第二次出现的bb

$ sed 's/bb/new-bb/2' file
1 aa 2 2 3 bb 5 new-bb 2 5

或更改第三次出现的 2

$ sed 's/2/12/3' file
1 aa 2 2 3 bb 5 bb 12 5

答案2

要更改行中第 n 个sed出现的位置,语法为s/pattern/replacement/3as已经由@HatLess展示

要更改整个输入中的第 nperl出现,您可以使用:

perl -pse 'if($n>0) {s{pattern}{--$n ? $& : "replacement"}ge}' -- -n=3

答案3

awk你一起可以做:

awk -v str='bb' -v pos=2 -v rplc='newBB' '
 {
   strPos=0
   for(i=1; i<=NF; i++)
       if($i==str && (++strPos==pos) ) { $i=rplc; break }
 }1' infile

输出:

1 aa 2 2 3 bb 5 newBB 2 5

注意:上面假设只有一个字符作为字段分隔符(默认:空格或制表符),否则连续的字段分隔符将挤成一个,或者您可以强制 awk 分别匹配每个单个字段分隔符(因此 FS 必须强制作为正则表达式模式):

awk -F'[\t]' -v OFS='\t' -v str='bb' -v pos=2 -v rplc='newBB' '
 {
   strPos=0
   for(i=1; i<=NF; i++)
      if($i==str && (++strPos==pos) ) { $i=rplc; break }
 }1' infile

注意:\t如果字段分隔符是空格字符,请更改为空格字符。


要更改整个输入中的第 n次出现(但我假设字段分隔符是制表符):

awk -F'[\t]' -v OFS='\t' -v str='bb' -v pos=2 -v rplc='newBB' '
 strPos!=2{
            for(i=1; i<=NF; i++)
                if($i==str && (++strPos==pos) ) { $i=rplc; break }
 }1' infile

答案4

我们可以用sed一个命令来完成这两个任务:

echo "1 aa 2 2 3 bb 5 bb 2 5"|sed -e "s/2/kop/3" -e "s/bb/pp/2"

此命令将替换第三次出现的2withkop和第二次出现的bbwith pp

相关内容