使用tac和sed反转文件

时间:2017-07-17 18:55:37

标签: linux bash sed scripting

我有一个用例,我需要搜索并替换文件中最后一个字符串,并将更改写回文件。下面的案例是该用例的简化版本:

我正在尝试撤消该文件,进行一些更改,然后再将其反转并写入该文件。我为此尝试了以下代码:

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

如何进行替换以及保留文件的顺序?

5 个答案:

答案 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'

编辑

或者只是在命令中添加另一个| tactac 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} })。