Sunday, March 13, 2022

[SOLVED] Replace text in file if previous line matches another text

Issue

My file looks like this:

FooBarA
foo bar
foo = bar
FooBarB
foo bar
foo = bar
FooBarC
foo bar
foo = bar
...

What I would like to do is to write a script that replaces the bar in foo = bar but only if it belongs to FooBarB. So in the example above only the second bar out of all foo = bar lines should be replaced.

I've played around with sed but I just can't get it done right. I would also like to avoid installing any tools that aren't necessarily pre-installed on the system (I'm on Mac OS), since the script will be used by other team members too.


Solution

One way to do it with sed (tested using macOS's sed and GNU sed), would be this:

replace.sed
#!/usr/bin/env sed -Ef

/FooBarB/,/^FooBar/ {
  s/(foo[[:space:]]*=[[:space:]]*).+/\1new-value/
}

Here's what it does:

  1. /FooBarB/,/^FooBar/ matches a range of lines where the first line matches the regex /FooBarB/ and the last line matches the regex /^FooBar/ (which is the start of the next "group"). The comma between the two regexes is the syntax for range matching in sed.

  2. s/(foo[[:space:]]*=[[:space:]]*).+/\1new-value/ — [s]ubstitutes (in the matched range of lines) whatever matches the regex (foo[[:space:]]*=[[:space:]]*).+ with \1new-value, where \1 references the first capturing group in the search regex. The search regex looks for foo followed by optional whitespace, followed by an = sign, followed again by whitespace and then whatever else is there, which in your case is the old value.

You could do it all in just one line, but I wanted to show a version that's a bit more digestible (as far as sed goes, in any case):

sed -E '/FooBarA/,/^FooBar/s/(foo[[:space:]]*=[[:space:]]*).+/\1new-value/' temp.md 


Answered By - IonuČ› G. Stan
Answer Checked By - Mary Flores (WPSolving Volunteer)