How to use sed to modify a line above or below matching pattern?

I couldn't figure out how to use sed or any other shell to do the following. Can anyone help? Thanks.

If seeing a string (e.g., TODAY) in the line,
replace a string in the line above (e.g, replace "Raining" with "Sunny")
and replace a string in the line below (e.g., replace "Reading" with "Hiking")

Maggie

Try:

perl -0pe 's/Raining(.*\n.*TODAY)/Sunny\1/g;s/(TODAY.*\n.*)Reading/\1Hiking/g' file
1 Like

sed is the stream oriented version of ed while ex is just ed extended...wonder why they didnt come up with a stream oriented version of ex :wink:

ex -s +'/TODAY/-1 s/Raining/Sunny/ | /TODAY/+1 s/Reading/Hiking/ | x' file

Thanks a lot! They both works.

can you explain what is "-0pe" and what "\1" mean in the command. thanks!

---------- Post updated 07-18-11 at 09:58 AM ---------- Previous update was 07-17-11 at 11:37 PM ----------

I need to go with Perl. but not familiar with this -0pe I need to replace the string in the file directly, can you help on how to modify the options to achieve that? Thanks a ton.

man perlrun
-p   causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed:
    LINE:
       while (<>) {
           ...             # your program goes here
        } continue {
        print or die "-p destination: $!\n";
        }

   If a file named by an argument cannot be opened for some reason, Perl warns you about it, and moves on to the next file.  
   Note that the lines are printed automatically.  An error occurring during printing is treated as fatal.  
   To suppress printing use the -n switch.  A -p overrides a -n switch.

   "BEGIN" and "END" blocks may be used to capture control before or after the implicit loop, just as in awk.
....
-0[octal/hexadecimal]
   specifies the input record separator ($/) as an octal or hexadecimal number.  
   If there are no digits, the null character is the separator.  
   Other switches may precede or follow the digits.  For example, if you have a version of find which 
   can print filenames terminated by the null character, you can say this:

                find . -name �*.orig� -print0  perl -n0e unlink

   The special value 00 will cause Perl to slurp files in paragraph mode.  
   The value 0777 will cause Perl to slurp files whole because there is no legal byte with that value.

   If you want to specify any Unicode character, use the hexadecimal format: "-0xHHH...", 
   where the "H" are valid hexadecimal digits.  (This means that you cannot use
   the "-x" with a directory name that consists of hexadecimal digits.)

....
-e commandline
    may be used to enter one line of program.  If -e is given, Perl will not look for a filename in the argument list.  
    Multiple -e commands may be given to build up a multi-line script.  
   Make sure to use semicolons where you would in a normal program.
1 Like

As for the "\1", it stores the first match contained in "()" brackets. To modify your file directly use this:

perl -i -0pe 's/Raining(.*\n.*TODAY)/Sunny\1/g;s/(TODAY.*\n.*)Reading/\1Hiking/g' file
1 Like

Thank you guys a lot.
While I do use unix for some very basic stuff, I did not know any perl or shell programming a couple of days ago. But I heard that perl or shell is good to solve my problem. Luckily I got it all worked out with your help. :slight_smile: