views:

391

answers:

4

Hello.

I'm writting a script to automate creating configuration files for Apache and PHP for my own webserver. I don't want to use any GUIs like CPanel or ISPConfig.

I have some templates of Apache and PHP configuration files. Bash script needs to read templates, make variable substitution and output parsed templates into some folder. What is the best way to do that? I can think of several ways. Which one is the best or may be there are some better ways to do that? I want to do that in pure Bash (it's easy in PHP for example)

1)http://stackoverflow.com/questions/415677/how-to-repace-variables-in-a-nix-text-file

template.txt:

the number is ${i}
the word is ${word}

script.sh:

#!/bin/sh

#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
    eval echo "$line"
done < "./template.txt"

BTW, how do I redirect output to external file here? Do I need to escape something if variables contain, say, quotes?

2) Using cat & sed for replacing each variable with it's value:

Given template.txt:

The number is ${i}
The word is ${word}

Command:

cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"

Seems bad to me because of the need to escape many different symbols and with many variables the line will be tooooo long.

Can you think of some other elegant and safe solution?

+1  A: 

I agree with using sed: it is the best tool for search/replace. Here is my approach:

$ cat template.txt
the number is ${i}
the dog's name is ${name}

$ cat replace.sed
s/${i}/5/
s/${name}/Fido/

$ sed -f replace.sed template.txt > out.txt

$ cat out.txt
the number is 5
the dog's name is Fido
Hai Vu
This requires temporary file for substitution string, right? Is there a way to do that without temporary files?
FractalizeR
@FractalizeR: Some versions of *sed* have a `-i` option (edit files in place) that is similar to the *perl* option. Check the manpage for your *sed*.
Chris Johnsen
Yes, I know. Thanks
FractalizeR
@FractalizeR Yes, sed -i will replace inline. If you are comfortable with Tcl (another scripting language), then check out this thread: http://stackoverflow.com/questions/2818130/in-tcl-how-do-i-replace-a-line-in-a-file/2837289#2837289
Hai Vu
+2  A: 

You can use this:

perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' template.txt

to replace all ${...} strings with corresponding enviroment variables (do not forget to export them before running this script).

For pure bash this should work (assuming that variables do not contain ${...} strings):

#!/bin/bash
while read line ; do
    while [[ "$line" =~ '(\$\{[a-zA-Z_][a-zA-Z_0-9]*\})' ]] ; do
        LHS=${BASH_REMATCH[1]}
        RHS="$(eval echo "\"$LHS\"")"
        line=${line//$LHS/$RHS}
    done
    echo $line
done
ZyX
I would change `[^}]` to `[A-Za-Z_][A-Za-z0-9_]` in the bash version to prevent the shell from going beyond strict substitution (e.g. if it tried to process `${some_unused_var-$(rm -rf $HOME)}`).
Chris Johnsen
@Chris Johnsen you are right, updated the answer.
ZyX
Is it safe if environment variable contains some quotes or backslashes or something? I mean perl version.
FractalizeR
@FractalizeR yes, it is safe. It will just fail, because perl does not do bash substitution. It only tries to find variable name in `%ENV` hash.
ZyX
ZyX
+1  A: 

For one approach to templating, see my answer here.

Dennis Williamson
+1  A: 

I'd have done it this way, probably less efficient, but easier to read/maintain.

TEMPLATE='/path/to/template.file'
OUTPUT='/path/to/output.file'

while read LINE; do
  echo $LINE |
  sed 's/VARONE/NEWVALA/g' |
  sed 's/VARTWO/NEWVALB/g' |
  sed 's/VARTHR/NEWVALC/g' >> $OUTPUT
done < $TEMPLATE
Craig552uk