Reputation: 133
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
Upvotes: 8
Views: 7511
Reputation: 3348
This is probably a slower solution than @John1024's but is a sed
-only solution that does not read the entire file into memory (it needs two passes though).
sed -i '$!N;/\n.*m11111/s/"\([^"]*\)"/"9243"/' filename
sed -i '1n; $!N;/\n.*m11111/s/"\([^"]*\)"/"9243"/' filename
As @John1024 pointed out, the first sed
replaces the previous content in quotes in-place if m11111
appears on an even-numbered line; the second one repeats the process, but ignores the first line to cover all odd-numbered lines.
Upvotes: 0
Reputation: 113834
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"/>
-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.
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.
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"/>
Upvotes: 15