Je dois créer des fichiers de configuration 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 dysfonctionnement 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 cherche une sorte de module de gabarit que je pourrais utiliser avec bash. Ce module de modèles utiliserait des scripts génériques conf et init.d pour en créer de nouveaux.
Avez-vous des indices pour cela? Sinon, je pourrais utiliser le moteur de templates python.
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
Module de modèle pour bash? Utilisez sed
, Luke! Voici un exemple d'une 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
$
vous pouvez le faire directement en bash, vous n'avez même pas besoin de sed. Ecrivez un script comme ça:
#!/bin/bash
cat <<END
this is a template
with $foo
and $bar
END
puis appelez-le comme suit:
foo=FOO bar=BAR ./template
Pour la génération de fichiers simple, faire essentiellement
. "${config_file}"
template_str=$(cat "${template_file}")
eval "echo \"${template_str}\""
suffirait.
Ici, ${config_file}
contient les variables de configuration au format analysable du shell, et ${template_file}
est le fichier de modèle qui ressemble au document Shell ici. La première ligne source dans le fichier ${config_file}
, la deuxième ligne place le contenu du fichier ${template_file}
dans la variable shell template_str
. Enfin, à la troisième ligne, nous construisons la commande Shell echo "${template_str}"
(où l'expression "${template_str}"
entre guillemets est développée) et nous l'évaluons.
Pour un exemple du contenu de ces deux fichiers, veuillez vous référer à https://serverfault.com/a/699377/120756 .
Il y a des limites à ce que vous pouvez avoir dans le fichier modèle ou vous devez exécuter l'échappement Shell. De même, si le fichier modèle est généré en externe, vous devez envisager, pour des raisons de sécurité, de mettre en place un filtrage approprié avant exécution afin de ne pas perdre vos fichiers, par exemple, lorsque quelqu'un injecte le fameux $(rm -rf /)
dans le fichier modèle.
Voici l'approche que j'ai finalement adoptée pour résoudre ce problème. Je l’ai trouvé un peu plus souple que certaines des approches ci-dessus et cela évite certains problèmes liés aux 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.
config:
THINGS=stuff
FIELDS="values work too!"
NEWLINES="those\\nnifty\\nlinebreaks"
résultat: Modèle rempli 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.
Perl
J'utilise Perl
pour remplacer les variables par leurs valeurs:
export world=World beautiful=wonderful
echo 'I love you, $world! You are $beautiful.' >my_template.txt
Perl -pe 's|\$([A-Za-z_]+)|$ENV{$1}|g' my_template.txt
La sortie: I love you, World! You are wonderful
.
my_template.txt
peut contenir des variables précédées de $
.
[Modifier] J'ai changé ma réponse par rapport à la réponse d'origine, c'était il y a des années.
J'aime la réponse de FooF ci-dessus: https://stackoverflow.com/a/30872526/3538173
Cependant, je préfère ne pas avoir de variable intermédiaire pour stocker tout le contenu du fichier modèle en mémoire.
. "${config_file}"
eval "echo \"$(cat "${template_file}")\""
Créez un fichier de modèle. Appelons-le example.tpl
:
Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!
Créez un fichier de configuration pour stocker vos variables. Appelons-le good.conf
:
NAME=John
WEATHER=good
Maintenant, dans le script où vous voulez rendre le modèle, vous pouvez écrire ceci:
#!/usr/bin/env bash
template_file=example.tpl
config_file=good.conf
. "${config_file}"
eval "echo \"$(cat "${template_file}")\""
# Or store the output in a file
eval "echo \"$(cat "${template_file}")\"" > out
Vous devriez voir cette magnifique sortie :)
Hello, John!
Today, the weather is good. Enjoy!
eval
Lorsque vous utilisez eval
, si le fichier de modèle contient des instructions, elles seront exécutées et cela peut être dangereux. Par exemple, changeons le example.tpl
ci-dessus avec ce contenu:
Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!
I'm a hacker, hu hu! Look, fool!
$(ls /)
Maintenant, si vous rendez votre fichier de modèle, vous verrez ceci:
Hello, John!
Today, the weather is good. Enjoy!
I'm a hacker, hu hu! Look, fool!
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
Maintenant, éditez votre fichier good.conf
pour avoir ce contenu:
NAME=$(ls -l /var)
WEATHER=good
et restituer le modèle. Vous devriez voir quelque chose comme ça:
Hello, total 8
drwxr-xr-x. 2 root root 6 Apr 11 04:59 adm
drwxr-xr-x. 5 root root 44 Sep 11 18:04 cache
drwxr-xr-x. 3 root root 34 Sep 11 18:04 db
drwxr-xr-x. 3 root root 18 Sep 11 18:04 empty
drwxr-xr-x. 2 root root 6 Apr 11 04:59 games
drwxr-xr-x. 2 root root 6 Apr 11 04:59 Gopher
drwxr-xr-x. 3 root root 18 May 9 13:48 kerberos
drwxr-xr-x. 28 root root 4096 Oct 8 00:30 lib
drwxr-xr-x. 2 root root 6 Apr 11 04:59 local
lrwxrwxrwx. 1 root root 11 Sep 11 18:03 lock -> ../run/lock
drwxr-xr-x. 8 root root 4096 Oct 8 04:55 log
lrwxrwxrwx. 1 root root 10 Sep 11 18:03 mail -> spool/mail
drwxr-xr-x. 2 root root 6 Apr 11 04:59 nis
drwxr-xr-x. 2 root root 6 Apr 11 04:59 opt
drwxr-xr-x. 2 root root 6 Apr 11 04:59 preserve
lrwxrwxrwx. 1 root root 6 Sep 11 18:03 run -> ../run
drwxr-xr-x. 8 root root 87 Sep 11 18:04 spool
drwxrwxrwt. 4 root root 111 Oct 9 09:02 tmp
drwxr-xr-x. 2 root root 6 Apr 11 04:59 yp!
Today, the weather is good. Enjoy!
I'm a hacker, hu hu! Look, fool!
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
swapfile
sys
tmp
usr
var
Comme vous pouvez le constater, l’injection de commandes dans les fichiers configuration et template est possible. C’est pourquoi vous devez faire très attention:
Imaginez que vous soyez un sudoer sans mot de passe, le rendu du fichier de modèle pourrait endommager votre système avec un rm -rf
bien placé.
Tant que vous contrôlez le contenu de ces fichiers, vous pouvez utiliser ce modèle eval
.
Si vous avez un fichier de configuration entrant externe (non approuvé), vous devez rechercher un moteur de modélisation qui isolera ce type d'injection. Par exemple, Jinja2 templating est assez célèbre en Python.
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 un mappage de cet espace réservé avec une valeur. Dans le code python, nous lisons le texte du modèle à partir du fichier, en créons un, puis substituons l’espace réservé par l’argument de ligne de commande.
Sinon, vous pouvez 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 de la variable d'environnement. X=A
définit la variable d'environnement sur la valeur souhaitée.
J'ai récemment publié un projet bash qui utilise précisément une syntaxe de modèle semblable à celle de jinja. Cela s'appelle cookie . Voici une démo: