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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10106292/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:00:26  来源:igfitidea点击:

Bash: how to use sed to replace only the last occurence in a file?

bashreplacesedawklast-occurrence

提问by Luca Borrione

Having a file containing repeated commented lines like:

有一个包含重复注释行的文件,例如:

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

I want to add a line only after the last occurence resulting in

我只想在最后一次出现后添加一行,导致

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

To do so I'm using this command:

为此,我正在使用此命令:

sed -i 's:^\(.*ScriptAlias /cgi-bin/.*\): \nScriptAlias /cgi-bin/ "mypath":' file

But this results in adding my line after each occurence like:

但这会导致在每次出现后添加我的行,例如:

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

How can I tell sed to replace only the last occurence?

EDITED:
If there's no way to solve it using sed (as said in comments), please provide alternatives reaching the same result, thanks.

我怎么能告诉 sed 只替换最后一次出现?

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



EDITED:
The repeated lines can be separeted and with other lines between them like



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

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

# ScriptAlias /cgi-bin/ "another-path"
ScriptAlias /foo/ "just-jump"
# ScriptAlias /cgi-bin/ "that's the last"

回答by glenn Hymanman

Use tacso you print your new line the firsttime you see the pattern:

使用tac以便在您一次看到模式时打印新行:

tac file | awk '/ScriptAlias/ && ! seen {print "new line"; seen=1} {print}' | tac

回答by Kent

alternative with awk:

用 awk 替代:

awk '/ScriptAlias \/cgi-bin\//{x=NR} {a[NR]=
kent$  echo "# ScriptAlias /cgi-bin/ "somepath"
fooo
# ScriptAlias /cgi-bin/ "otherpath"
bar
"|awk '/ScriptAlias \/cgi-bin\//{x=NR} {a[NR]=
# ScriptAlias /cgi-bin/ somepath
fooo
# ScriptAlias /cgi-bin/ otherpath
$$$here comes new line$$$
bar
;}END{for(i=1;i<=NR;i++){if(i==x+1)print "$$$here comes new line$$$"; print a[i];}}'
;}END{for(i=1;i<=NR;i++){if(i==x+1)print "$$$here comes new line$$$"; print a[i];}}' file

test:

测试:

tail -r temp | awk '{line="yourline"}{if(
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(
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
~/ScriptAlias/&&last==0){print line"\n"
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
;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>
~/ScriptAlias/&&last==0){print line"\n"##代码##;last=1}else print}' | tail -r

output:

输出:

##代码##

回答by Vijay

##代码##

tested below:

测试如下:

##代码##

回答by pizza

It is a task for the editor.

这是编辑的任务。

##代码##

In last occurence mode.

在最后出现模式下。

##代码##