2

I need to do a set of substitution within the text file E.g putting instead of following key string

#include "martini.itp"

3 another strings with accurate paths to the itp files

#include "../dir1/dir2/martini1.itp"
#include "../dir1/dir2/martini2.itp"
#include "../dir1/dir2/martini3.itp"

I have tried to realize it using below pattern which produced errors I guess because the characters like ../ should be isolated from sed statement using specified syntax.

sed -i 's/#include "martini.itp"/#include "../dir1/dir2/martini_v2.0_lipids_all_201506.itp"\n#include "../dir1/dir2/martini_v2.0_ions.itp"\n#include "../dir1/dir2/martini_v2.0_solvents.itp"/' topol.top
3
  • Don't you need to escape spaces as well? \ Commented Mar 10, 2016 at 11:28
  • You need to either use different delimiters for the substitution or escape all the forward slashes. Commented Mar 10, 2016 at 11:35
  • right I need to escape ../ within the SED statement. How I could do it correctly on my example 7 Commented Mar 10, 2016 at 11:35

3 Answers 3

3

If you're working with fixed strings, you can just use awk and avoid having to escape anything (well, except some double quotes):

awk '$0 == "#include \"martini.itp\"" { 
    $0 = "#include \"../dir1/dir2/martini1.itp\"" ORS \
         "#include \"../dir1/dir2/martini2.itp\"" ORS \
         "#include \"../dir1/dir2/martini3.itp\""
}
{ print }' file > tmp && mv tmp file

If the line matches, replace it with the other lines. A quite common shorthand is to replace { print } with 1, as 1 is true and { print } is the default action.

To use sed, I'd go for something like this:

sed -i.bak '/#include "martini\.itp"/i\
#include "../dir1/dir2/martini1.itp"\
#include "../dir1/dir2/martini2.itp"\
#include "../dir1/dir2/martini3.itp"
d' file

This inserts the lines you want, then d deletes the original line. Using -i.bak creates a backup of your original file, which is something I'd always recommend.

Sign up to request clarification or add additional context in comments.

1 Comment

You can use a single print statement in the first part and maintain readability
0

You should escape . by writing \. and change regex delimiter from / to : just to prevent some problem of regex delimiter collision with your file path. So finally, you should get something like this:

Regex:

$'s:#include "martini\.itp":#include "../dir1/dir2/martini_v2.0_lipids_all_201506.itp"\\\n#include "../dir1/dir2/martini_v2.0_ions.itp"\\\n#include "../dir1/dir2/martini_v2.0_solvents.itp":' 

Run:

sed -i '' $'s:#include "martini\.itp":#include "../dir1/dir2/martini_v2.0_lipids_all_201506.itp"\\\n#include "../dir1/dir2/martini_v2.0_ions.itp"\\\n#include "../dir1/dir2/martini_v2.0_solvents.itp":' topol.top

Output:

#include "../dir1/dir2/martini_v2.0_lipids_all_201506.itp"
#include "../dir1/dir2/martini_v2.0_ions.itp"
#include "../dir1/dir2/martini_v2.0_solvents.itp"

Note that there is some trick here to escape newline by adding $ to the beginning of regex and use \\\n instead of \n.

2 Comments

You don't need to escape .s i nthe replacement part.
You also don't need to triple escape the newlines. \n is enough.
0

You need to escape the " . ' and / characters by putting \ before each instance. Also '$'/n for the newline

sed -i 's/#include \"martini\.itp\"/#include \"\.\.\/dir1\/dir2\/martini1.itp\"'$'\\n#include \"\.\.\/dir1\/dir2\/martini2.itp\"\\n#include \"\.\.\/dir1\/dir2\/martini3.itp\"/g' topol.top

Comments