4

I want to go recursively through a directory and search for specific content in all files. The content should then be replaced if found. With a single line I would make something like this:

find . -type f -exec sed -i -e 's@code2replace@@g' {} \;

It sometimes worked and sometimes not (not sufficient hard drive space ...). Now I would need something for a multine replacement. The orignal file should be overwritten and the multiline pattern could be rather long. So perhaps storing in an external file would be easier I think.

The code which should be replaced looks like the following:

#c3284d#
echo(gzinflate(base64_decode("sylOLsos....")));
#/c3284d#

Also which characters do I have to escape?

1 Answer 1

4

Sed can do a lot of things beside simple search-and-replace, and that includes multiline support.

Here's a blog post on how someone did this (he wrote a sedml script for "sed multiline": http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/

The basic idea is to copy the whole file to sed's "hold buffer", run the regex on that and then write out the changed file. However, this approach may be rather slow if your files are large as you're loading a whole file at a time into memory.

4
  • For your other question on what you have to escape: as long as you use single-quotes in the shell, and the pattern does not contain any more # characters between the delimiters (which I wouldn't expect in a base64_encoded string), you should be able to do 's@#c3284d#[^#]*#/c3284d#@@g' with no further escaping. The only things you'd need to escape within the quotes are sed metacharacters and the s delimiter (@ in this case so you're ok).
    – user21105
    Commented Aug 9, 2012 at 10:46
  • Where do I store the sedml script and how do I add it to the bash path? What does [^#]* in the middle mean? How does the final command look like? grep -rl '#c3284d#' * | while read i; do sedml $i 's@#c3284d#[^#]*#/c3284d#@@g' $i.tmp; done;? Does it overwrite the existing file? Are there any cases the replacement would not work (e.g. when something is missing between the two patterns)?
    – testing
    Commented Aug 9, 2012 at 11:09
  • 1
    1. I'd personally make a directory bin in your home directory and put all your own scripts in there, then to add it to your path you can add export PATH="$PATH:~/bin" to one of your startup files (.bashrc). 2. [^#]* : The brackets usually mean 'any of these characters', except that the caret at the beginning turns it into 'any except these characters'. So [^#] matches any character that's not a #. The * at the end means "any number of", so you're matching any sequence of characters that doesn't contain a #. running out of space ...
    – user21105
    Commented Aug 9, 2012 at 15:06
  • 1
    3. The command is correct like that. You can change the $i.tmp to just $i at the end to overwrite the files in-place (if you look at the sedml script, it uses $1.tmp to make the changes and then moves the file to $2 at the end, if successful). 4. The command as given will work if the delimiters are exactly as given and there's no # symbols between the delimiters. (You may want to check that it works correctly on one or two files manually, sedml FILE 's@#c3284d#[^#]*#/c3284d#@@g' FILE.tmp and see if the result is what you expect (this version doesn't overwrite the original).
    – user21105
    Commented Aug 9, 2012 at 15:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .