Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have this config file I want to edit programatically. I always use sed to make small changes, but now I need to replace 1 line for multiple lines, something like this:

some code
# maintenance placeholder
more code

Change it into this

some code
maintenance line 1
maintenance line 2
maintenance line 2
more code

How can I do that?

share|improve this question
    
sed supports multiple lines, (you don't need a \n or anything you just type enter (without closing the quotes)) If this doesn't answer your question I'm unsure as to what it is you want. – u8sand Feb 1 '13 at 23:11
    
@u8sand What if the code has quotes too? Escaping everything will be a chore. – ChocoDeveloper Feb 1 '13 at 23:51
    
indeed it will be, what programming or scripting language were you hoping to use? I recommend a utility that accepts different files containing, the input text, what you are looking for and what to replace it with. for instance: cat file.old.conf | replacer -s search.txt -r replace.txt > file.new.conf – u8sand Feb 3 '13 at 17:36
up vote 2 down vote accepted

I went ahead and created a little utility for you in C++, I hope it comes useful to you. Simply compile it and enjoy.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(int argc,char *argv[])
{
    fstream i,
                    s,
                    r,
                    o;
    string s_str,
                 r_str,
                 buf;
    int n;
    char ch,
             s_in = 1,
             s_out = 1;

    for(int n = 1; n < argc; n += 2)
    {
        if(argv[n][0] == '-')
        {
            switch(argv[n][1])
            {
                case 'i':
                    i.open(argv[n+1], fstream::in);
                    s_in = 0;
                    break;
                case 's':
                    s.open(argv[n+1], fstream::in);
                    break;
                case 'r':
                    r.open(argv[n+1], fstream::in);
                    break;
                case 'o':
                    o.open(argv[n+1], fstream::out);
                    s_out = 0;
                    break;
                default:
                    cerr << "Usage: helper [-i input_file] <-s search_file> <-r replace_file> [-o output_file]";
                    return 0;
            }
        }
    }
    if(!s_in && !i.is_open())
    {
        cerr << "Input could not be opened.";
        return -1;
    }
    if(!s.is_open())
    {
        cerr << "Search could not be opened.";
        return -1;  
    }
    if(!r.is_open())
    {
        cerr << "Replace could not be opened.";
        return -1;
    }
    if(!s_out && !o.is_open())
    {
        cerr << "Output could not be opened.";
        return -1;
    }

    /* get s and r in memory */
    while((ch = s.get()) != EOF)
        s_str += ch;
    s.close();
    while((ch = r.get()) != EOF)
        r_str += ch;
    r.close();

    buf = "";
    while((s_in ? (ch = cin.get()) : (ch = i.get())) != EOF)
    {
        buf += ch;
        for(n = 0; n < buf.length(); n++)
            if(buf.at(n) != s_str.at(n))
            {
                s_out ? (cout << buf) : (o << buf);
                buf = "";
                break;
            }
        if(n == s_str.length())
        {
            s_out ? (cout << r_str) : (o << r_str);
            buf = "";
        }
    }
    s_out ? (cout << buf) : (o << buf);

    if(!s_in)
        i.close();
    if(!s_out)
        o.close();

    return 0;
}

Compiled with:

g++ -o replacer replacer.cpp

Sample Usage:

input.txt:

1
2
3
4
5

search.txt

3

replace.txt

Three

Command

./replacer -i input.txt -s search.txt -r replace.txt -o output.txt

output.txt

1
2
Three
4
5

If you have any further questions, please ask. I do hope it accomplishes what you wanted it to do. (It also accepts stdin, and outputs to stdout if you ommit -i and -o) Of course newlines, quotes, ect.. will cause no problem because they are in separate files.

share|improve this answer

In case @u8sand’s answer (comment) isn’t clear enough for you, you can do what you describe by

sed '/# maintenance placeholder/c\
maintenance line 1\
maintenance line 2\
'

You can do the same thing in s commands:

sed 's/SuperUser/Super\
User/'

Perhaps, as u8sand suggests, there are versions of sed where the backslashes are not required.

share|improve this answer

If you have perl, try using:

perl -pi.bak -e 's/oldtext/newtext/' file.txt

this will replace 'oldtext' with 'newtext' in file.txt, and will create a backup of file called file.txt.bak

share|improve this answer

You must log in to answer this question.

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