9

I have a large file which has special characters in it. There is a multi line code there, that I want to replace with sed.

This:

  text = "\
    ------                                                           ------\n\n\
    This message was automatically generated by email software\n\
    The delivery of your message has not been affected.\n\n\
    ------                                                           ------\n\n"

Needs to turn into this:

text = ""

I tried the following code, but no luck:

sed -i '/  text = "*/ {N; s/  text = .*affected.\./  text = ""/g}' /etc/exim.conf

It does not replace anything and does not display any error messages

I have been playing with it, but everything I try does not work.

don_crissti
  • 82,805
  • Does it need to be sed or are you open to other tools? Can there be " inside the text= block? Can there be other cases of text = in your file? Will there always be 4 lines of text or can there be more/less? – terdon Feb 19 '16 at 12:42
  • Preferably sed, or anything that does not require installation in a CentOS server. Out of the box tools – blade19899 Feb 19 '16 at 12:43
  • @terdon There are not other text = in the folder, the out come needs to be text = "". The files has 891 lines of code. SO, it needs te respect the other text. – blade19899 Feb 19 '16 at 12:45
  • do you want to overwrite the file or just modify the output? – joH1 Feb 19 '16 at 12:45
  • @Moonstroke NO OVERWRITE. It just needs to replace the text - as seen in my question - to text = "". As seen in my question. – blade19899 Feb 19 '16 at 12:47

3 Answers3

17

Perl to the rescue:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ will edit the file "in place", leaving a backup copy
  • -0777 reads the whole file at once, not line by line

The substitution s/// works similarly as in sed (i.e. it matches text = " followed by anything but double quotes many times up to a double quote), but in this case, it works on the whole file.

choroba
  • 47,233
6

You have to check the pattern space and keep pulling in the Next line if it doesn't match e.g.

sed '/text = "/{              # if line matches text = "
:b                            # label b
$!N                           # pull in the next line (if not the last one)
/"$/!bb                       # if pattern space doesn't end with " go to label b
s/".*"/""/                    # else remove everything between the quotes
}' infile

with gnu sed you can write it as

sed '/text = "/{:b;$!N;/"$/!bb;s/".*"/""/}' infile

That's not very efficient though, better just select the range /text = "/,/"/, modify the first line and delete the rest:

sed '/text = "/,/"/{            # in this range
/text = "/!d                    # delete all lines not matching text = "
s/\\/"/                         # replace the backslash with quotes (this is only
}' infile                       # executed if the previous d wasn't executed)

again, with gnu sed you can write it as a one-liner:

sed '/text = "/,/"/{/text = "/!d;s/\\/"/}' infile
don_crissti
  • 82,805
3

Personally, I would do this in Perl. If we can assume that there are no " before the closing ", you can do:

perl -0pe 's/(text\s*=\s*)".*?"/$1""/s' file

The -0 slurps the entire file, reading it into memory. The -p means "print every line (here, a "line" will be the entire file) after applying the script given by -e". The script itself is a simple substitution operator. It will capture the string text followed by 0 or more whitespace characters, an = and 0 or more whitespace again (text\s*=\s*) and save it as $1. Then, it will replace the captured pattern as well as the shortest quoted string it finds with the pattern ($1) and "". The s flag makes . match newlines.

terdon
  • 242,166