在多个文件中将每 4 次出现的字符“_”替换为“@”

cat*_*123 2 bash perl awk sed

我试图用 bash 在多个文件中将每 4 次出现的“_”替换为“@”。

例如

foo_foo_foo_foo_foo_foo_foo_foo_foo_foo.. 
Run Code Online (Sandbox Code Playgroud)

会成为

foo_foo_foo_foo@foo_foo_foo_foo@foo_foo...

#perl -pe 's{_}{++$n % 4 ? $& : "@"}ge' *.txt 
Run Code Online (Sandbox Code Playgroud)

我尝试过 perl 但问题是这会替换从最后一个文件开始的每 4 个 _ 。例如,某些文件的第一个 _ 被替换,因为它不是以计数 0 开始每个新文件,而是从前一个文件继续。

我努力了:

#awk '{for(i=1; i<=NF; i++) if($i=="_") if(++count%4==0) $i="@"}1' *.txt 
Run Code Online (Sandbox Code Playgroud)

但这也行不通。

使用 sed 我无法找到一种方法来继续替换每 4 次出现的情况,因为每个文件中有不同数量的 _ 。有些文件有 20 个 _,有些文件有 200 个 _。因此,我无法指定一个范围。

我真的迷失了该怎么办,有人可以帮忙吗?

Sha*_*awn 5

您只需要重置 perl 中的计数器即可eof告诉它何时完成读取每个文件:

perl -pe 's{_}{++$n % 4 ? "_" : "@"}ge; $n = 0 if eof' *.txt
Run Code Online (Sandbox Code Playgroud)


Ed *_*ton 5

这可能就是您想要的,使用 GNU awk for RT:

$ awk -v RS='_' '{ORS=(FNR%4 ? RT : "@")} 1' file
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo..
Run Code Online (Sandbox Code Playgroud)

_一次仅将每个 - 分隔的字符串读取到内存 1 中,因此无论您的输入文件有多大,假设_其中有 s ,都应该可以工作。

它假设您想要替换_整个文件中的每 4 个字符,而不是单个行中的字符。