如何在BASH中查找和替换匹配的每个偶数外观



我使用sed -i 's/AAA/ZZZ/g' filename将文件中每次出现的"AAA"替换为"ZZZ"。我需要将"AAA"的每个偶数外观替换为"ZZZ",例如:

This is a AAA sentence. AAA
This is another AAA sentence.
This is yet AAA another AAA sentence.
This is AAA stillAAA AAA yet AAA another AAA sentence.

这将变成:

This is a AAA sentence. ZZZ
This is another AAA sentence.
This is yet ZZZ another AAA sentence.
This is ZZZ stillAAA ZZZ yet AAA another ZZZ sentence.

如何替换匹配的每个偶数外观?

下面是一个简短的gnu awk版本

awk '{ORS=NR%2==0?"ZZZ":RS}1' RS="AAA" file
This is a AAA sentence. ZZZ
This is another AAA sentence.
This is yet ZZZ another AAA sentence.
This is ZZZ stillAAA ZZZ yet AAA another ZZZ sentence.

awk是比sed更好的工具。考虑一下这个awk命令:

awk -F 'AAA' '{for (i=1; i<NF; i++) {OFS=c%2?"ZZZ":FS; printf "%s%s", $i, OFS; c++}
    print $NF}' file
This is a AAA sentence. ZZZ
This is another AAA sentence.
This is yet ZZZ another AAA sentence.
This is ZZZ stillAAA ZZZ yet AAA another ZZZ sentence.

该awk将输入字段分隔符设置为AAA,并根据计数器是奇数还是偶数在AAAZZZ之间切换输出字段分隔符。每次计数器为偶数时,OFS被设置为AAA,而当计数器为奇数时,则OFS被设为ZZZ

这里有一个perl解决方案:

$ cat inp
This is a AAA sentence. AAA
This is another AAA sentence.
This is yet AAA another AAA sentence.
This is AAA stillAAA AAA yet AAA another AAA sentence.
$ perl -pe 'my $line = "" ; while(<>){ $line=$line.$_} $line =~ s/(.*?AAA.*?)AAA/1ZZZ/mgs; print $line;' < inp
This is another AAA sentence.
This is yet ZZZ another AAA sentence.
This is ZZZ stillAAA ZZZ yet AAA another ZZZ sentence.

在这里,首先我将整个文件累积在一个变量$line中&然后,我用ZZZ替换AAA的每个交替出现;使用非贪婪匹配。

Perl:

perl -wpe 'BEGIN{$/="AAA"} $.%2 or s/AAA/ZZZ/' foo.txt

您也可以使用sed

sed -n -e '1,$ { 
:oddline  s/AAA/n/g; :odd  s/n/AAA/m; t even ;p;N;s/.*n//;b oddline ; 
:evenline s/AAA/n/g; :even s/n/ZZZ/m; t odd ; p;N;s/.*n//;b evenline ; 
}' << _END_
This is a AAA sentence. AAA
This is another AAA sentence.
This is yet AAA another AAA sentence.
This is AAA stillAAA AAA yet AAA another AAA sentence.
_END_

sed脚本遍历所有行并记住奇数/偶数替换(跨行)。在模式空间中,所有AAA首先用换行符替换,然后一次用AAA或ZZZ替换一个。为了切换到下一行,它首先被附加(N),然后删除前一行(s/.*n//)。

sed "1 h;1 !H;$ {x;l;s/=/=e/g;s/²/=c/g;s/AAA/²/g;s/²([^²]{1,})²/²1ZZZ/g;s/²/AAA/g;s/=c/²/g;s/=e/=/g;}" YourFile

使用替换(由于AAA可能在a.*内部)确保即使有替换字符在内部,也可以在之前和之后进行双重翻译

这可能对你有用(GNU sed):

sed -r ':a;$!{N;ba};/x00/q1;s/AAA/x00/g;s/(x00)([^x00]*)1/AAA2ZZZ/g' file

这会将文件拖入内存,然后用一个唯一字符替换所有出现的AAA。然后,该唯一字符的每一次奇数和偶数出现分别被CCD_ 15和CCD_ 16代替。

注意:如果unique character不是唯一的,则不对文件进行任何更改,并设置1的错误代码。

第二种方法比较冗长,但可用于更改第N个值,并且不依赖于unique value:

sed  -r 's/AAA/n&/g;/n/!b;G;:a;s/$/#/;s/#{2}$//;/n$/s/nAAA/nZZZ/;s/n//;/n.*n/ba;P;s/^.*n//;h;d' file

它将所需模式的出现次数存储在保留空间中,并在遇到具有这种模式的行时检索它。

最新更新