场景是我想使用 注释掉 shell 脚本中最后一次出现的单词sed
。
假设我有temp.sh
以下内容:
Abc 123 Abc
Sdf 2
Abc
Abc
Utyr
Qww
我想将最后一个实例Abc
(发生在行的开头)替换为#Abc
所以最后,结果将是这样的:
Abc 123 Abc
Sdf 2
Abc
#Abc
Utyr
Qww
答案1
反转文件,注释掉第一个,然后再次反转文件:
$ tac temp.sh | sed '0,/^Abc/{s/^Abc/#&/}' | tac
Abc 123 Abc
Sdf 2
Abc
#Abc
Utyr
Qww
这意味着“从第 0 行开始,继续直到第一行匹配/^Abc/
,并且仅在这些行中,替换Abc
为#
以及匹配的任何内容 ( #
),在本例中为Abc
。感谢这个答案。
请注意,这需要tac
一个 GNU 工具以及 的 GNU 实现sed
。
要对原始文件进行更改,请使用:
tac temp.sh | sed '0,/^Abc/{s/^Abc/#&/}' | tac > temp1.sh &&
mv temp1.sh temp.sh
或者,在 Perl 中:
$ tac temp.sh | perl -pe 'next if $k; $k++ if s/^Abc/#$&/ ' | tac
Abc 123 Abc
Sdf 2
Abc
#Abc
Utyr
Qww
要对原始文件进行更改,请使用:
tac temp.sh | perl -pe 'next if $k; $k++ if s/^Abc/#$&/ ' | tac> temp1.sh &&
mv temp1.sh temp.sh
或者使用Stephane 的纯粹perl
方法或者善行清净sed
者,两者都用于-i
编辑原始文件。
答案2
$ sed -e 'H; $!d' -e 'g; s/\n\(.*\n\)\(Abc\)/\1#\2/' file
Abc 123 Abc
Sdf 2
Abc
#Abc
Utyr
Qww
这会将整个文件读取到 的保留空间中sed
,对其进行修改并输出修改后的文本。
前两个sed
表达式H
和$!d
,将每一行附加到保留空间,然后跳到下一个循环(除非我们处于输入的最后一行)。
该g
命令针对最后一行执行并获取保留空间的内容。然后,替换会删除其中的初始换行符(将第一行附加到空保留空间),并#
在最后一次出现换行符之前Abc
插入一个字符。
我们保证得到最后的 Abc
在换行符之后,因为.*
是贪婪的,因此会尽可能匹配。
您可以使用-i
就地编辑文件(使用 GNU sed
,使用 BSDsed
则需要-i '.bak'
):
sed -i'.bak' -e 'H; $!d' -e 'g; s/\n\(.*\n\)\(Abc\)/\1#\2/' file
与ed
编辑:
$ printf '%s\n' '1;?^Abc?;s//#&/' ,p Q | ed -s file
Abc 123 Abc
Sdf 2
Abc
#Abc
Utyr
Qww
ed
这本质上是使用单个编辑命令来执行编辑1;?^Abc?;s//#&/
。该命令首先将光标移动到文件的第一行(1
;如果字符串Abc
位于最后一行,则这是必要的),然后向后搜索^Abc
文件中正则表达式的最后一个匹配项(?^Abc?
)。一旦找到,它就会#
在找到的行的开头插入一个字符(s//#&/
;这会重用最近匹配的正则表达式,并用于&
在之后插入该行的匹配部分#
)。
尾随的,p
andQ
命令将整个缓冲区打印到标准输出,然后无条件退出。
答案3
有awk
(无管道):
awk -v str=Abc '
NR==FNR{if ($0 == str) nr_str=NR; next}
{print (FNR == nr_str) ? "#"$0 : $0}
' file file
输出
Abc 123 Abc
Sdf 2
Abc
#Abc
Utyr
Qww
答案4
使用awk
:
反转文件,使用thenawk
的函数。sub()
之后再次反转文件会给出预期的输出。
$ tac file |
awk '/^Abc/ && (!found){sub(/^Abc/, "#Abc"); found++}1' |
tac
输出
Abc 123 Abc
Sdf 2
Abc
#Abc
Utyr
Qww
不带管道:
$ awk '
BEGIN{rec_rep=""; rec_last=""}
{if (/^Abc/){
if (rec_rep) print rec_rep;
rec_rep = $0;
sub(/^Abc/, "#Abc");
rec_last = $0;
}
else { rec_rep = ((rec_rep) ? rec_rep ORS : "") $0;
rec_last = ((rec_last) ? rec_last ORS : "") $0 }
}
END{print rec_last}' file