10

So, I have a bunch of files in a directory, and I need to insert a line of text into each of them. They have essentially the following format:


<VirtualHost *:80>
        ServerAdmin gabe@localhost
        DocumentRoot /var/www/test1
        ServerName test1.local
        ServerAlias test1
        <Directory "/var/www/test1">
                Options All
                AllowOverride All
        </Directory>
</VirtualHost>

And I'd like to insert a line before the closing

</VirtualHost>
tag. My first assumption is that I should be able to do this with sed, probably matching and replacing that tag. I'm going to start attempting this now, but if anyone has a existing way to do this, I'd love to hear it.

  • I'll be honest when I say I think this is more of a programming task... and thus should be on SO. I'd use Perl to do it, esp since I bet there's a perl module designed to parse, and modify apache configs. – xenoterracide Aug 24 '10 at 19:22
  • 2
    Thanks, but it's a task that should be easy to accomplish with simple unix tools, hence asked here. Thanks for your comment, though. – gabe. Aug 24 '10 at 19:30
10

Something like this:

sed 's/<\/VirtualHost>/yourlinehere\n<\/VirtualHost>/'

works. If you want to repeat this command on a lot of file you can do something like:

for i in *; do sed -i 's/<\/VirtualHost>/yourlinehere\n<\/VirtualHost>/' "$i"; done

Probably better (but untested) thanks to @ChrisDown:

find . -type f -print0 | while IFS= read -r -d '' filename;\
do sed -i 's/<\/VirtualHost>/yourlinehere\n<\/VirtualHost>/' $filename;\ 
done
  • awesome... this is just what I was looking for. – gabe. Aug 24 '10 at 19:29
  • 1
    Do not parse ls. Use a glob instead. mywiki.wooledge.org/ParsingLs – Chris Down Nov 14 '11 at 15:36
  • You are rigth @ChrisDown. Please, improve my answer. – lcipriani Nov 23 '11 at 14:14
  • Choosing a different character than / for the sed expression is cleaner, since you don't have to escape the slash: 's:</VirtualHost>:yourlinehere\n</VirtualHost>:' – Alexander Jun 28 '13 at 11:06
2

If you don't mind Perl try:

perl -pi'*.old' -e 's(</VirtualHost>(Your stuff here\n</VirtualHost>)' myfile

The -i switch will save your old file with a .old extension and print to the current one.

2

You can also use "ex" (command-line vi) if the editing you want to do is even somewhat complicated. For example, you only want to do the insert for on one instance of "".

A shell script like this can work:

for FILENAME in *.whatever  # Need a criteria to glob, or a list of names
do
    ex -s $FILENAME << END_EDITS
/^<\/VirtualHost>/
O " capital-o, not zero
text to insert goes here
.
w!
q
END_EDITS
done

This approach gives you the advantages of "ex": finding a location with elaboarte patterns, and 'cursor movements'. You can do things like find a pattern, then find the next instance, THEN do the insert. Or you can change text, rather than just doing inserts. Or you can change between ranges. Don't forget that "ex" lets you use "." as the current line, so .,/^somepatter/s/blah/foo/ will work.

0

You can use the following single line code to insert a single line or multiple lines into a given location in a file, in you case before 'VirtualHost'. The code basically searches for the filename (it could be *.*, if you want to insert the texts in all files) within the given directory and its sub-directories. Within the files found, it searches for the pattern 'VirtualHost'. After it found the pattern, it replaces it with firstline\nsecondline\notherlines\n\VirtualHost. Note that 'VirtualHost' is part of the text for replacement, otherwise we will loss it.

find directory/ -name filename -print | xargs sed -i 's|VirtualHost|firstline\nsecondline\notherlines\nVirtualHost|g'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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