Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace content of previous line after finding a match using sed

Tags:

bash

sed

I am trying to replace content in the previous line of a search.

My file:

<RECORD>
<TOKEN data = "670"/>
<ID data ="10647043"/>
<NAME data="m11111"/>

Here if I search for m11111, then I need to go to the previous line and replace 10647043 with a different value. Sed that I tried:

sed '/m11111/{g;/=/s/=.*/="9283"\/>/g;};h' test.txt

Is there a way with sed? If not with sed, any other way to do it ?

Thanks Ajay

like image 874
Ajay Avatar asked Jul 20 '16 00:07

Ajay


People also ask

How can I replace text after a specific word using sed?

Find and replace text within a file using sed command Use Stream EDitor (sed) as follows: sed -i 's/old-text/new-text/g' input.txt. The s is the substitute command of sed for find and replace. It tells sed to find all occurrences of 'old-text' and replace with 'new-text' in a file named input.txt.

How do you use sed to substitute a new line?

The `sed` command can easily split on \n and replace the newline with any character. Another delimiter can be used in place of \n, but only when GNU sed is used. When the \n is missing in the last line of the file, GNU sed can avoid printing \n. Furthermore, \n is usually added to each consecutive output of `sed`.

How do you replace a variable in a file using sed?

In this syntax, you just need to provide the string you want to replace at the old string and then the new string in the inverted commas. After that, provide the file in which you want to find and replace the mentioned string.

What does \b mean in sed?

\b marks a word boundary, either beginning or end. Now consider \b' . This matches a word boundary followed by a ' . Since ' is not a word character, this means that the end of word must precede the ' to match.


1 Answers

GNU sed

Assuming that test.txt is not gigabytes in size and that you have GNU sed (gsed on a Mac), try:

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

How it works

  • -z

    This tells sed to read the whole file at once. Technically, it reads until NUL characters but, since no sensible text file has NUL characters, this is in practice the same as reading the whole file.

  • -E

    This tells sed to use extended regular expressions so that we don't have to type so many backslashes.

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

    This looks for 10647043 followed any any character except a newline, followed by a newline, followed any characters except a newline, follwed by m11111. This replace the 10647043 with 9283, keeping everything else the same.

BSD (OSX) sed

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

The change here is the use of H;1h;$!d;x to read the whole file in at once.

Using awk

This reads in just one line at a time. If the current line contains m11111, then the previous line (stored in the variable last) is modified.

$ 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"/>
like image 57
John1024 Avatar answered Sep 23 '22 08:09

John1024