web-dev-qa-db-fra.com

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

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.

43
iwalktheline

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
67
dogbane

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
$ 
40
user405725

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 
20
Kim Stebel

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.

10
FooF

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.
5
Keegs

Solution élégante et courte en une ligne avec 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 $.

1
kyb

[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}")\""

Exemple

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!

Attention avec 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:

  • soyez sûr du contenu du fichier modèle: vérifiez qu'il n'y a PAS d'injection de commande.
  • soyez sûr du contenu du fichier de configuration: vérifiez qu'il n'y a pas non plus d'injection de commande. Si le fichier de configuration provient de quelqu'un d'autre, vous devez connaître et faire confiance à cette personne avant de générer le modèle.

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.

1
Samuel Phan

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.

0
Alexey

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:

 cookie demo

0
Bryan Bugyi