我想通过 linux 命令替换文件中最后 5 次出现的字符串。
请指教。
例子:
输入ababa ababa ababa ababa ababa ababa
替换aba
为abX
预期输出:ababa abXba abXba abXba abXba abXba
输入被ababa ababa ababa ababa ababa ababa ababa
替换aba
为12
执行的输出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
.对于e
,replacement
被解释为 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