使用sed找到匹配项后替换上一行的内容

Aja*_*jay 5 bash sed

我正在尝试替换搜索的前一行中的内容。

我的档案:

<RECORD>
<TOKEN data = "670"/>
<ID data ="10647043"/>
<NAME data="m11111"/>
Run Code Online (Sandbox Code Playgroud)

在这里,如果我搜索m11111,则需要转到上一行并将10647043替换为其他值。我尝试过的Sed:

sed '/m11111/{g;/=/s/=.*/="9283"\/>/g;};h' test.txt
Run Code Online (Sandbox Code Playgroud)

sed有办法吗?如果不使用sed,还有其他方法吗?

谢谢阿杰

Joh*_*024 8

GNU sed

假设test.txt大小不是千兆字节,并且您已将GNU sed(在Mac上为gs),请尝试:

$ sed -zE 's/10647043([^\n]*\n[^\n]*m11111)/9283\1/' test.txt
<RECORD>
<TOKEN data = "670"/>
<ID data ="9283"/>
<NAME data="m11111"/>
Run Code Online (Sandbox Code Playgroud)

怎么运行的

  • -z

    这告诉sed一次读取整个文件。从技术上讲,它会读取直到NUL个字符,但是,由于没有明智的文本文件包含NUL字符,因此实际上与读取整个文件相同。

  • -E

    这告诉sed使用扩展的正则表达式,这样我们就不必键入太多的反斜杠。

  • s/10647043([^\n]*\n[^\n]*m11111)/9283\1/

    这将查找10647043,其后跟换行符之外的任何其他字符,然后是换行符,然后是除换行符之外的所有字符,并跟随m11111。这将10647043替换为9283,其他所有内容保持不变。

BSD(OSX)sed

sed -E 'H;1h;$!d;x; s/10647043([^\n]*\n[^\n]*m11111)/9283\1/' test.txt
Run Code Online (Sandbox Code Playgroud)

此处的更改是使用H;1h;$!d;x一次读取整个文件。

使用awk

一次只读取一行。如果当前行包含m11111,则last修改前一行(存储在变量中)。

$ awk '/m11111/{sub(/10647043/, "9283", last)} NR>1{print last} {last=$0} END {print last}' test.txt
<RECORD>
<TOKEN data = "670"/>
<ID data ="9283"/>
<NAME data="m11111"/>
Run Code Online (Sandbox Code Playgroud)

  • +1为awk解决方案。出于明显的易读性,可移植性,效率等明显原因,切勿将sed用于多行输入。 (2认同)