Bash:如何使用sed仅替换文件中最后一次出现的内容?

Bash:如何使用sed仅替换文件中最后一次出现的内容?,bash,replace,sed,awk,last-occurrence,Bash,Replace,Sed,Awk,Last Occurrence,包含重复注释行的文件,如: # ScriptAlias /cgi-bin/ "somepath" # ScriptAlias /cgi-bin/ "otherpath" 我只想在最后一次出现导致 # ScriptAlias /cgi-bin/ "somepath" # ScriptAlias /cgi-bin/ "otherpath" ScriptAlias /cgi-bin/ "mypath" 为此,我使用以下命令: sed -i 's:^\(.*ScriptAlias /cgi-bin/

包含重复注释行的文件,如:

# ScriptAlias /cgi-bin/ "somepath"
# ScriptAlias /cgi-bin/ "otherpath"
我只想在最后一次出现导致

# ScriptAlias /cgi-bin/ "somepath"
# ScriptAlias /cgi-bin/ "otherpath"
ScriptAlias /cgi-bin/ "mypath"
为此,我使用以下命令:

sed -i 's:^\(.*ScriptAlias /cgi-bin/.*\):\1 \nScriptAlias /cgi-bin/ "mypath":' file
但这会导致在每次发生后添加我的行,如:

# ScriptAlias /cgi-bin/ "somepath"
ScriptAlias /cgi-bin/ "mypath"
# ScriptAlias /cgi-bin/ "otherpath"
ScriptAlias /cgi-bin/ "mypath"
我如何告诉sed只替换最后一次发生的事件?

编辑:
如果使用sed无法解决问题(如评论中所述),请提供达到相同结果的替代方案,谢谢



已编辑
重复的行可以分开,并且在它们之间有其他行,如

# ScriptAlias /cgi-bin/ "somepath"
# ScriptAlias /cgi-bin/ "otherpath"

# ScriptAlias /cgi-bin/ "another-path"
ScriptAlias /foo/ "just-jump"
# ScriptAlias /cgi-bin/ "that's the last"
awk替代方案:

awk '/ScriptAlias \/cgi-bin\//{x=NR} {a[NR]=$0;}END{for(i=1;i<=NR;i++){if(i==x+1)print "$$$here comes new line$$$"; print a[i];}}' file
使用,以便在第一次看到图案时打印新行:

tac file | awk '/ScriptAlias/ && ! seen {print "new line"; seen=1} {print}' | tac
测试如下:

krithika.337> cat temp
# ScriptAlias /cgi-bin/ "somepath" 
# ScriptAlias /cgi-bin/ "otherpath" 
# ndmxriptAlias /cgi-bin/ "otherpath" 
# ScriptAlias /cgi-bin/ "otherpath" 
# bdjiptAlias /cgi-bin/ "otherpath" 
krithika.338> tail -r temp | awk '{line="yourline"}{if($0~/ScriptAlias/&&last==0){print line"\n"$0;last=1}else print}' | tail -r
# ScriptAlias /cgi-bin/ "somepath" 
# ScriptAlias /cgi-bin/ "otherpath" 
# ndmxriptAlias /cgi-bin/ "otherpath" 
# ScriptAlias /cgi-bin/ "otherpath" 
yourline
# bdjiptAlias /cgi-bin/ "otherpath" 
krithika.339>

这是编辑的任务

ex input_file << "DONE"
/ScriptAlias \/cgi-bin\/ "otherpath"
a
ScriptAlias /cgi-bin/ "mypath"
.
:1
/ScriptAlias \/cgi-bin\/ "another-path"
a
ScriptAlias /cgi-bin/ "just-jump"
.
:x
DONE

ex-input\u文件这不是sed的作业。也许是awk,但我会用Python或Perl来完成。@MK.Ok。。我要求sed是因为我在使用它。如果使用sed无法解决此问题,则欢迎使用任何其他方法。谢谢,你可以用sed来做,我认为这并不理想。我个人觉得这是一个很好的主意,而且仍然很容易阅读。我对它进行了一点个性化,并添加了直接写入文件的功能,(有没有办法将您的解决方案与interactive-I一起使用?)。我的命令最后是
tac$file | awk'/ScriptAlias\/cgi-bin\/&!seen{print“ScriptAlias/cgi-bin/\“mypath\”;seen=1}{print}{tac>“/var/lock/${file}”和&mv”/var/lock/${file}”“${file}”
不能直接写入输入文件。您必须使用临时文件(正如您所做的那样)。这就是
sed-i
在后台所做的事情gnu tail(来自coreutils)没有
-r
选项。
tail -r temp | awk '{line="yourline"}{if($0~/ScriptAlias/&&last==0){print line"\n"$0;last=1}else print}' | tail -r
krithika.337> cat temp
# ScriptAlias /cgi-bin/ "somepath" 
# ScriptAlias /cgi-bin/ "otherpath" 
# ndmxriptAlias /cgi-bin/ "otherpath" 
# ScriptAlias /cgi-bin/ "otherpath" 
# bdjiptAlias /cgi-bin/ "otherpath" 
krithika.338> tail -r temp | awk '{line="yourline"}{if($0~/ScriptAlias/&&last==0){print line"\n"$0;last=1}else print}' | tail -r
# ScriptAlias /cgi-bin/ "somepath" 
# ScriptAlias /cgi-bin/ "otherpath" 
# ndmxriptAlias /cgi-bin/ "otherpath" 
# ScriptAlias /cgi-bin/ "otherpath" 
yourline
# bdjiptAlias /cgi-bin/ "otherpath" 
krithika.339>
ex input_file << "DONE"
/ScriptAlias \/cgi-bin\/ "otherpath"
a
ScriptAlias /cgi-bin/ "mypath"
.
:1
/ScriptAlias \/cgi-bin\/ "another-path"
a
ScriptAlias /cgi-bin/ "just-jump"
.
:x
DONE
ex input_file << "DONE"
$
?ScriptAlias \/cgi-bin\/ "otherpath"
a
ScriptAlias /cgi-bin/ "mypath"
.
$
?ScriptAlias \/cgi-bin\/ "another-path"
a
ScriptAlias /cgi-bin/ "just-jump"
.
:x
DONE