如何通过Linux命令替换文件中最后五次出现的字符串?

如何通过Linux命令替换文件中最后五次出现的字符串?

我想通过 linux 命令替换文件中最后 5 次出现的字符串。

请指教。

例子:

输入ababa ababa ababa ababa ababa ababa
替换abaabX
预期输出:ababa abXba abXba abXba abXba abXba

输入被ababa ababa ababa ababa ababa ababa ababa
替换aba12
执行的输出ababa ababa 12ba 12ba 12ba 12ba 12ba

注意:该字符串可以跨越多行,也可以位于文件中的任何位置。但只想替换最后 5 个匹配项

如果文件中有 100 个匹配项,则将替换最后 5 个匹配项。

答案1

perl

perl -0777 -pse '
  $count = () = /\Q$string\E/g;
  s{\Q$string\E}{$count-- > $n ? $& : $replacement}ge
  ' -- -string='whatever
even multiple
lines' -replacement='whatever as well' -n=5 -- file

添加就地-i编辑的选项file,而不是在标准输出上发送结果。

  • -p是针对文件中的所有记录评估传递到的表达式sed中的代码的模式。e-e
  • -0777将记录分隔符设置为不可能的字节值,这意味着只有一条记录:文件的完整内容。
  • -s允许将变量值作为-varname=value参数传递。
  • /regexp/g,是 的缩写$_ =~ m{regexp}g,全局应用于当前记录(在 中)的 atcher,regexp如果正则表达式在标量上下文中匹配,并且匹配列表在列表上下文中匹配,则返回 true/false。这里的正则表达式是,并且是m$_\Q$string\E\Q\E引用$string即使它包含正则表达式运算符,so也会被视为文字字符串。
  • 使用() = /regexp/g,我们强制使用列表上下文,这里通过分配给一个空变量列表,因此本质上丢弃它们,但由于结果用于标量分配,这给你元素的数量,因此正则表达式的匹配数量,因此$string记录中出现的次数( 的全部内容file)。
  • s{regexp}{replacement}ge:s替换g全局regexp匹配的replacement.对于ereplacement被解释为 perl 代码表达式。
  • condition ? iftrue : iffalse是大多数语言中常见的 C 三元运算符。
  • $count--返回$count之前增量。如果< $n我们替换为$&包含匹配的内容,则不执行任何操作,如果不替换为$replacement

答案2

这是使用 awk 和 sed 的一种方法。通过以下方式计算字符串在文件中出现的次数:

grep -o mystring file1.txt | wc -l

假设这个数字是 20。现在用任意字符串替换前 20-5=15 次出现,例如 PWWP

awk '{for(i=1;i<=NF;i++){if(c<15&&$i=="mystring"){c++;sub("mystring","PWWP",$i)}}}1' file1.txt > file2.txt

使用 sed 从 file2.txt 中删除所有剩余的匹配项(其中 5 个):

sed -i 's/mystring//g' file2.txt

并通过第二个 sed 操作恢复原始文件:

sed -i 's/PWWP/mystring/g' file2.txt
mv file2.txt file1.txt

相关内容