Créer un nouveau fichier à partir de modèles avec le script bash

Je dois créer des fichiers conf et init.d qui sont très similaires. Ces fichiers permettent de déployer un nouveau service http sur mes serveurs. Ces fichiers sont les mêmes et seuls certains paramètres changent d'un fichier à l'autre (listen_port, Domaine, chemin sur le serveur...).

Comme toute erreur dans ces fichiers conduit à un mauvais fonctionnement du service, je voudrais créer ces fichiers en utilisant un script bash.

Par exemple:

generate_new_http_service.sh 8282 subdomain.domain.com /home/myapp/rootOfHTTPService

Je suis à la recherche d'une sorte de module de Template que je pourrais utiliser avec bash. Ce le module de modèle utiliserait une conf générique et init.d scripts pour en créer de nouveaux.

Avez-vous des indices pour cela? Sinon, je pourrais utiliser le moteur Python templating.

40
demandé sur guaka 2011-06-02 16:52:08

7 réponses

Vous pouvez le faire en utilisant un heredoc. par exemple

Generate.sh:

#!/bin/sh

#define parameters which are passed in.
PORT=$1
DOMAIN=$2

#define the template.
cat  << EOF
This is my template.
Port is $PORT
Domain is $DOMAIN
EOF

Sortie:

$ generate.sh 8080 domain.com

This is my template.
Port is 8080
Domain is domain.com

Ou enregistrez - le dans un fichier:

$ generate.sh 8080 domain.com > result
65
répondu dogbane 2011-06-02 13:23:54

Module modèle pour bash? Utilisez sed, Luke! Voici un exemple de l'un des millions de façons possibles de le faire:

$ cat template.txt 
#!/bin/sh

echo Hello, I am a server running from %DIR% and listening for connection at %HOST% on port %PORT% and my configuration file is %DIR%/server.conf

$ cat create.sh 
#!/bin/sh

sed -e "s;%PORT%;$1;g" -e "s;%HOST%;$2;g" -e "s;%DIR%;$3;g" template.txt > script.sh

$ bash ./create.sh 1986 example.com /tmp
$ bash ./script.sh 
Hello, I am a server running from /tmp and listening for connection at example.com on port 1986 and my configuration file is /tmp/server.conf
$ 
39
répondu Christian Toffolo 2014-01-27 15:09:00

Vous pouvez le faire directement dans bash, vous n'avez même pas besoin de sed. Ecrire un script comme ça:

#!/bin/bash

cat <<END
this is a template
with $foo
and $bar
END

Alors appelez-le comme ceci:

foo=FOO bar=BAR ./template 
18
répondu Kim Stebel 2011-06-02 13:24:25

Pour la génération de fichiers simple, en faisant essentiellement

 . "${config_file}"
 template_str=$(cat "${template_file}")
 eval "echo \"${template_str}\""

Suffirait.

Ici ${config_file} contient les variables de configuration au format shell analysable, et ${template_file} est le fichier modèle qui ressemble au document shell here. La première ligne de sources dans le fichier ${config_file}, la deuxième ligne met le contenu du fichier ${template_file} dans la variable shell template_str. Enfin, dans la troisième ligne, nous construisons la commande shell echo "${template_str}" (où l'expression entre guillemets doubles "${template_str}" est développée) et évaluons il.

Pour un exemple du contenu de ces deux fichiers, veuillez vous référer à la https://serverfault.com/a/699377/120756.

Il y a des limites à ce que vous pouvez avoir dans le fichier de modèle ou vous devez effectuer un échappement de shell. De plus, si le fichier modèle est produit en externe, pour des raisons de sécurité, vous devez envisager d'implémenter un filtrage approprié avant l'exécution afin que vous ne perdiez pas vos fichiers lorsque quelqu'un injecte le fameux $(rm -rf /) dans le fichier. fichier de modèle.

8
répondu FooF 2017-04-13 12:13:38

Voici l'approche que j'ai fini par prendre pour résoudre ce problème. Je l'ai trouvé un peu plus flexible que certaines des approches ci-dessus, et cela évite certains des problèmes avec les citations.

Fill.sh:

#!/usr/bin/env sh

config="$1"
template="$2"
destination="$3"

cp "$template" "$destination"

while read line; do
    setting="$( echo "$line" | cut -d '=' -f 1 )"
    value="$( echo "$line" | cut -d '=' -f 2- )"

    sed -i -e "s;%${setting}%;${value};g" "$destination"
done < "$config"

Modèle:

Template full of important %THINGS%

"Note that quoted %FIELDS% are handled correctly"

If I need %NEWLINES% then I can add them as well.

Configuration:

THINGS=stuff
FIELDS="values work too!"
NEWLINES="those\\nnifty\\nlinebreaks"

Résultat: Modèle plein de choses importantes

"Note that quoted "values work too!" are handled correctly"

If I need those
nifty
linebreaks then I can add them as well.
2
répondu Keegs 2018-02-06 00:41:12

Voici comment je l'ai fait pour moi-même:

. "${config_file}"
eval "cat << EOF
$(cat ${template_file})
EOF"

Et si vous voulez le mettre dans un fichier de configuration:

. "${config_file}"
eval "cat > /etc/MY_SERVICE/MY_CONFIG << EOF
$(cat ${template_file})
EOF"

De cette façon, vous n'avez pas besoin de créer de variable supplémentaire.

0
répondu Samuel Phan 2015-10-07 15:55:29

Vous pouvez utiliser la classe python string.Template

$ echo 'before $X after' > template.txt

$ python  -c 'import string; print(string.Template(open("template.txt").read()).substitute({"X":"A"}))'

before A after

Ou

$  python  -c 'import string, sys; print(string.Template(open("template.txt").read()).substitute({"X":sys.argv[1]}))' "A"

Ici $X est un espace réservé dans le modèle et {"X":"A"} est une cartographie de l'espace réservé à une valeur. Dans le code python, nous lisons le texte du modèle à partir du fichier, en créons un modèle, puis substituons l'espace réservé à l'argument de ligne de commande.

Vous pouvez également utiliser L'ERB de Ruby, si Ruby est installé sur votre machine.

$ echo "before <%= ENV['X'] %> after" > template.txt

$ X=A erb template.txt

before A after

Ici <%= ENV['X'] %> est un espace réservé. ENV['X'] Lit la valeur du variable d'environnement. X=A définit la variable d'environnement à la valeur désirée.

0
répondu Alexey 2016-02-13 20:30:04