Replace a line with multiple lines in a file
Asked Answered
C

3

10

I want to replace a single line in a file with multiple lines, e.g., I want to replace a particular function call, say,

foo(1,2)

with

if (a > 1) {  
    foo(1,2)  
} else {  
    bar(1,2)  
}

How can I do it in bash?

Chris answered 14/5, 2012 at 1:27 Comment(1)
what if I want to change it inplace in my current file without creating any extra file.Chris
D
9

This is what the sed s command was built for:

shopt -s extglob

ORIG="foo(1,2)"
REP="if (a > 1) {  
      foo(1,2)  
} else {  
      bar(1,2)  
}"

REP="${REP//+(
)/\\n}"

sed "s/$ORIG/$REP/g" inputfile > outputfile

Note that the REP="${REP//\+( )/\\n}" lines are only needed if you want to define the REP in the formatted way that I did on line two. It might be simpler if you just used \n and \t in REP to begin with.

Edit: Note! You need to escape ' and \ as well in your REP if you have them.

Edit in response to the OP's question

To change your original file without creating a new file, use sed's --in-place flag, like so:

sed --in-place "s/$ORIG/$REP/g" inputfile

Please be careful with the --in-place flag. Make backups before you run it because all changes will be permanent.

Dilute answered 14/5, 2012 at 2:26 Comment(5)
shopt -s extglob is required and the backslash before the plus sign needs to be removed.Nikitanikki
@DennisWilliamson Thanks for catching that. I forget sometimes that most people don't have extended globbing turned on by default. The backslash was just leftover from testing.Dilute
It is working, but I am not sure what this meant REP="${REP//+( )/\\n}"Chris
@Chris It's a from of Parameter Substitution called "Global Replacement".Dilute
Note if you e.g. have an apostrophe in your REP it will also brake sed. You will get something like: sed: -e expression #1, char 320: unknown option to `s'Delano
F
0

This might work for you:

cat <<\! |
> a
> foo(1,2)
> b
> foo(1,2)
> c
> !
> sed '/foo(1,2)/c\
> if (a > 1) {\
>     foo(1,2)\
> } else {\
>     bar(1,2)\
> }' 
a
if (a > 1) {
    foo(1,2)
} else {
    bar(1,2)
}
b
if (a > 1) {
    foo(1,2)
} else {
    bar(1,2)
}
c
Falco answered 14/5, 2012 at 13:12 Comment(0)
W
0

To replace strings in-place in a file, you can use ed (as conveniently tagged in the question). Assuming your input file looks like this:

line before
foo(1,2)
line between
    foo(1,2)
line after

You can write a script to do the substitution and store it in a file such as script.ed:

%s/\([[:blank:]]*\)foo(1,2)/\1if (a > 1) {\
\1    foo(1,2)\
\1} else {\
\1    bar(1,2)\
\1}/
w
q

Notice that this takes indentation into account; every line is prepended with whatever blanks were there before the function call in the original file, so the result would look like this:

$ ed -s infile < script.ed
$ cat infile
line before
if (a > 1) {
    foo(1,2)
} else {
    bar(1,2)
}
line between
    if (a > 1) {
        foo(1,2)
    } else {
        bar(1,2)
    }
line after

Should the function call not be on a line on its own but potentially prepended by other characters that shouldn't be removed, you could use this as the first line of the substitution:

%s/\([[:blank:]]*\)\(.*\)foo(1,2)/\1\2if (a > 1) {\

So this

    } something; foo(1,2)

would become

    } something; if (a > 1) {
        foo(1,2)
    } else {
        bar(1,2)
    }

with indentation still properly accounted for.

Wilhelmstrasse answered 30/5, 2018 at 17:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.