Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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
add comment

3 Answers

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
add comment

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
add comment

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
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.