web-dev-qa-db-fra.com

Templating avec Linux dans un script shell?

ce que je veux accomplir c'est:

1.) Avoir un fichier de configuration comme modèle, avec des variables comme $ version $ path (par exemple config Apache)

2.) Avoir un script Shell qui "remplit" les variables du modèle et écrit le fichier généré sur le disque.

Est-ce possible avec un script Shell. Je serais très reconnaissant si vous pouvez nommer quelques commandes/outils que je peux accomplir ceci ou quelques bons liens.

29
Markus

C'est très possible. Un moyen très simple de l'implémenter serait que le fichier modèle soit réellement le script et utilise des variables Shell telles que

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
cat > /tmp/destfile <<-EOF
here is some config for version $version which should
also reference this path $path
EOF

Vous pouvez même rendre cela configurable sur la ligne de commande en spécifiant version=$1 et path=$2, vous pouvez donc l'exécuter comme bash script /foo/bar/baz 1.2.3. Le - avant EOF provoque des espaces avant que les lignes soient ignorées, utilisez _ <<EOF si vous ne souhaitez pas ce comportement.

Une autre façon de procéder serait d'utiliser la fonctionnalité de recherche et de remplacement de sed

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
sed -e "s/VERSION/$version/g" -e "s/PATH/$path/" /path/to/templatefile > /tmp/destfile

qui remplacerait chaque instance des chaînes VERSION et PATH. S'il y a d'autres raisons pour lesquelles ces chaînes se trouveraient dans le fichier modèle, vous pouvez effectuer votre recherche et les remplacer par VERSION ou% VERSION% ou quelque chose de moins susceptible d'être déclenché accidentellement.

24
mtinberg

Aucun outil nécessaire autre que /bin/sh. Étant donné un fichier modèle du formulaire

Version: ${version}
Path: ${path}

ou même avec un code Shell mixte inclus

Version: ${version}
Path: ${path}
Cost: ${cost}\$
$(i=1; for w in one two three four; do echo Param${i}: ${w}; i=$(expr $i + 1); done)

et un fichier de configuration analysable Shell comme

version="1.2.3-r42"
path="/some/place/under/the/Rainbow/where/files/dance/in/happiness"
cost="42"

il est simple de l'étendre à

Version: 1.2.3-r42
Path: /some/place/under/the/Rainbow/where/files/dance/in/happiness
Cost: 42$
Param1: one
Param2: two
Param3: three
Param4: four

En effet, étant donné le chemin d'accès au fichier de configuration dans la variable Shell config_file et le chemin d'accès au fichier modèle dans template_file, il vous suffit de:

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

C'est peut-être plus joli que d'avoir un script Shell complet comme fichier modèle (solution de @ mtinberg).

Le programme d'extension de modèles naïf complet:

#!/bin/sh

PROG=$(basename $0)

usage()
{
    echo "${PROG} <template-file> [ <config-file> ]"
}

expand()
{
    local template="$(cat $1)"
    eval "echo \"${template}\""
}

case $# in
    1) expand "$1";;
    2) . "$2"; expand "$1";;
    *) usage; exit 0;;
esac

Cela produira l'extension à la sortie standard; redirigez simplement la sortie standard vers un fichier ou modifiez ce qui précède de manière évidente pour produire le fichier de sortie souhaité.

Mises en garde: L'expansion du fichier modèle ne fonctionnerait pas si le fichier contenait des guillemets doubles non échappés ("). Pour des raisons de sécurité, nous devrions probablement inclure des vérifications de cohérence évidentes ou, mieux encore, effectuer une transformation d'échappement Shell si le fichier modèle est généré par une entité externe.

19
FooF

La manière la plus simple de le faire simplement dans Linux CLI est d'utiliser envsubst et les variables d'environnement.

Exemple de fichier modèle Apache.tmpl:

<VirtualHost *:${PORT}>
    ServerName ${SERVER_NAME}
    ServerAlias ${SERVER_ALIAS}
    DocumentRoot "${DOCUMENT_ROOT}"
</VirtualHost>

Exécutez envsubst et affichez le résultat dans un nouveau fichier my_Apache_site.conf:

export PORT="443"
export SERVER_NAME="example.com"
export SERVER_ALIAS="www.example.com"
export DOCUMENT_ROOT="/var/www/html/"
envsubst < Apache.tmpl > my_Apache_site.conf

Production:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot "/var/www/html/"
</VirtualHost>
14
Lirt

J'utilise shtpl pour cela. (mon projet privé, ce qui signifie qu'il n'est pas largement utilisé. Mais peut-être voulez-vous le tester quand même)

Par exemple, vous voulez générer un/etc/network/interfaces à partir d'un fichier csv, vous pouvez le faire comme ça:

Contenu du fichier CSV (ici test.csv):

eth0;10.1.0.10;255.255.0.0;10.1.0.1
eth1;192.168.0.10; 255.255.255.0;192.168.0.1

Modèle (ici interfaces.tpl):

#% IFS=';'
#% while read "Val1" "Val2" "Val3" "Val4"; do
auto $Val1 
iface $Val1 inet static
  address $Val2 
  netmask $Val3 
  gateway $Val4 

#% done < "$CSVFILE"

Commander:

$ CSVFILE=test.csv sh -c "$( shtpl interfaces.tpl )"

Résultat:

auto eth0 
iface eth0 inet static
  address 10.1.0.10 
  netmask 255.255.0.0 
  gateway 10.1.0.1 

auto eth1 
iface eth1 inet static
  address 192.168.0.10 
  netmask  255.255.255.0 
  gateway 192.168.0.1

Prendre plaisir!

4
zstegi

Vous devriez probablement examiner un système de gestion de configuration comme Puppet ou Chef . Ceux-ci peuvent facilement faire ce que vous décrivez ci-dessus et beaucoup plus.

4
EEAA

Si vous voulez des modèles légers et réels plutôt que du code Shell qui génère de nouveaux fichiers, les choix habituels sont sed & awk ou Perl. Voici un lien: http://savvyadmin.com/generate-text-from-templates-scripts-and-csv-data/

Moi, j'utiliserais un vrai langage comme Perl, tcl, python, Ruby ou autre chose dans cette classe. Quelque chose construit pour les scripts. Ils ont tous de bons outils de création de modèles simples et des tonnes d'exemples dans google.

4
Mark

J'ai amélioré la réponse de FooF pour que l'utilisateur n'ait pas besoin d'effacer manuellement les guillemets doubles:

#!/bin/bash
template="$(cat $1)"
template=$(sed 's/\([^\\]\)"/\1\\"/g; s/^"/\\"/g' <<< "$template")
eval "echo \"${template}\""
2
Shaohua Li

J'ai récemment publié un script bash qui accomplit exactement cela en utilisant une syntaxe de modèle de type jinja. Cela s'appelle cookie . Voici une démo:

cookie demo

1
Bryan Bugyi

Je suis probablement en retard à cette fête. Cependant, je suis tombé sur le même problème et j'ai opté pour la création de mon propre moteur de modèle BASH en quelques lignes de code:

Disons que vous avez cette file.template:

# My template
## Author
 - @NAME@ <@EMAIL@>

Et ce fichier rules:

NAME=LEOPOLDO WINSTON
EMAIL=leothewinston\@leoserver.com

Vous exécutez cette commande:

templater rules < file.template

Vous obtenez ceci:

# My template
## Author
 - LEOPOLDO WINSTON <[email protected]>

Vous pouvez l'installer en:

 bpkg install vicentebolea/bash-templater

Ceci est le projet site

0
Vicente Bolea

Pour développer la grande réponse de @ FooF (les nouvelles lignes n'ont pas été formatées dans les commentaires), en utilisant un caractère de contrôle hérédoc +, vous pouvez autoriser des caractères arbitraires et noms de fichiers:

template() {
    # if [ "$#" -eq 0 ] ; then return; fi # or just error
    eval "cat <<$(printf '\x04\x04\x04');
$(cat $1)
"
}

Cela accepte tout caractère non nul et ne tronque tôt que si 3 ^D Octets sont rencontrés sur leur propre ligne (en réalité jamais). zsh prend même en charge les terminateurs nuls, donc printf '\x00\x00\x00' fonctionnerait. template fonctionne même pour les noms de fichiers perfides comme:

for num in `seq 10`; do
    template 'foo "$ .html' # works
done

Attention, les modèles Shell peuvent "étendre" des commandes arbitraires, par exemple $(launch_nukes.sh --target $(curl -sL https://freegeoip.app/csv/ | cut -d, -f 9,10)). Avec une grande puissance…

Edit: si vous ne voulez vraiment pas que vos fichiers lancent des armes nucléaires, juste Sudo -u nobody sh (Ou un autre utilisateur sûr) au préalable.

0
alexchandel