我有一个用例,我需要搜索并替换文件中最后一个字符串,并将更改写回文件。下面的案例是该用例的简化版本:
我正在尝试撤消该文件,进行一些更改,然后再将其反转并写入该文件。我为此尝试了以下代码:
tac test | sed s/a/b/ | sed -i '1!G;h;$!d' test
test是一个包含内容的文本文件:
a
1
2
3
4
5
我原本希望这个命令不会改变文件的顺序,但它实际上已将内容反转为:
5
4
3
2
1
b
如何进行替换以及保留文件的顺序?
答案 0 :(得分:2)
尝试cat test | rev | sed -i '1!G;h;$!d' | rev
或者您只能使用sed
例如,您想要替换ABC
上的DEF
:
你需要添加'到你的sed结尾:
sed -e 's/\(.*\)ABC/\1DEF/g'
这告诉sed替换你的正则表达式的每一个匹配项("全局")而不是仅替换第一次出现。
如果你想确保它正在替换线路上最后一次出现的ABC,你还应该添加一个$
:
sed -e 's/\(.*\)ABC$/\1DEF/g'
编辑
或者只是在命令中添加另一个| tac
:
tac test | sed s/a/b/ | sed -i '1!G;h;$!d' | tac
答案 1 :(得分:2)
您可以tac
您的文件,在第一次出现所需模式时应用替换,tac
再次tee
结果到临时文件,然后使用原始名称重命名:
tac file | sed '0,/a/{s//b/}' | tac > tmp && mv tmp file
答案 2 :(得分:2)
另一种方法是让用户grep
获取包含您要更改的文本的最后一行的编号,然后使用sed
更改该行:
$ linno=$( grep -n 'abc' <file> | tail -1 | cut -d: -f1 )
$ sed -i "${linno}s/abc/def/" <file>
答案 3 :(得分:1)
以下是使用awk
在单个命令中执行此操作的方法。
第一个输入文件:
cat file
a
1
2
3
4
a
5
现在这个awk命令:
awk '{a[i++]=$0} END{p=i; while(i--) if (sub(/a/, "b", a[i])) break;
for(i=0; i<p; i++) print a[i]}' file
a
1
2
3
4
b
5
要将输出保存回原始文件,请使用:
awk '{a[i++]=$0} END{p=i; while(i--) if (sub(/a/, "b", a[i])) break;
for(i=0; i<p; i++) print a[i]}' file >> $$.tmp && mv $$.tmp f
答案 4 :(得分:1)
awk中的另一个人。首先是一个测试文件:
$ cat file
a
1
a
2
a
和解决方案:
$ awk '
$0=="a" && NR>1 { # when we meet "a"
print b; b="" # output and clear buffer b
}
{
b=b (b==""?"":ORS) $0 # gether the buffer
}
END { # in the end
sub(/^a/,"b",b) # replace the leading "a" in buffer b with "b"
print b # output buffer
}' file
a
1
a
2
b
通过将输出重定向到替换原始文件(awk ... file > tmp && mv tmp file
)的临时文件或者如果您使用的是GNU awk v.4.1.0+,可以使用inplace edit({{1} })。