J'écris un script pour automatiser la création de fichiers de configuration pour Apache et PHP pour mon propre serveur Web. Je ne veux pas utiliser d'interface graphique comme CPanel ou ISPConfig.
J'ai quelques modèles de fichiers de configuration Apache et PHP. Le script Bash doit lire les modèles, effectuer une substitution de variable et générer des modèles analysés dans un dossier. Quelle est la meilleure façon de le faire? Je peux penser à plusieurs façons. Laquelle est la meilleure ou peut-être existe-t-il de meilleures façons de le faire? Je veux faire ça en pure Bash (c'est facile en PHP par exemple)
1) Comment remplacer les espaces réservés $ {} dans un fichier texte?
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, comment rediriger la sortie vers un fichier externe ici? Dois-je échapper à quelque chose si les variables contiennent, par exemple, des guillemets?
2) Utilisation de cat & sed pour remplacer chaque variable par sa valeur:
Template.txt donné:
The number is ${i}
The word is ${word}
Commander:
cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"
Cela me semble mauvais à cause de la nécessité d'échapper à de nombreux symboles différents et avec de nombreuses variables, la ligne sera trop longue.
Pouvez-vous penser à une autre solution élégante et sûre?
la source
Réponses:
Vous pouvez utiliser ceci:
pour remplacer toutes les
${...}
chaînes par les variables d'environnement correspondantes (n'oubliez pas de les exporter avant d'exécuter ce script).Pour le pur bash, cela devrait fonctionner (en supposant que les variables ne contiennent pas de chaînes $ {...}):
. Solution qui ne se bloque pas si RHS fait référence à une variable qui se réfère à elle-même:
AVERTISSEMENT : je ne connais pas un moyen de gérer correctement les entrées avec les NUL dans bash ou de préserver la quantité de retours à la ligne de fin. La dernière variante est présentée telle quelle car les shells «aiment» l'entrée binaire:
read
interprétera les contre-obliques.read -r
n'interprétera pas les contre-obliques, mais supprimera quand même la dernière ligne si elle ne se termine pas par une nouvelle ligne."$(…)"
supprimera autant de nouvelles lignes de fin qu'il y en a, donc je termine…
par; echo -n a
et j'utiliseecho -n "${line:0:-1}"
: cela supprime le dernier caractère (qui esta
) et préserve autant de nouvelles lignes de fin qu'il y en avait dans l'entrée (y compris non).la source
[^}]
pour[A-Za-Z_][A-Za-z0-9_]
dans la version bash pour empêcher le shell d'aller au-delà de la substitution stricte (par exemple s'il essayait de traiter${some_unused_var-$(rm -rf $HOME)}
).$&
dans la solution Perl en""
: d'abord laisse${...}
intact si elle ne parvient pas à se substituer, ensuite le remplace par une chaîne vide.while
boucle lise la dernière ligne même si elle n'est pas terminée par une nouvelle ligne, utilisezwhile read -r line || [[ -n $line ]]; do
. En outre, votreread
commande supprime les espaces de début et de fin de chaque ligne; pour éviter cela, utilisezwhile IFS= read -r line || [[ -n $line ]]; do
\
échappant).Essayer
envsubst
la source
envsubst
n'est pas nécessaire lors de l'utilisation d'un heredoc car bash traite l'heredoc comme une chaîne littérale entre guillemets doubles et interpole déjà les variables qu'il contient. C'est un excellent choix lorsque vous souhaitez lire le modèle à partir d'un autre fichier. Un bon remplacement pour les beaucoup plus encombrantsm4
.envsubst
est un utilitaire GNU gettext, et n'est en fait pas très robuste (puisque gettext est destiné à localiser les messages humains). Plus important encore, il ne reconnaît pas les substitutions $ {VAR} échappées par une barre oblique inverse (vous ne pouvez donc pas avoir un modèle qui utilise des substitutions $ VAR au moment de l'exécution, comme un script shell ou un fichier de configuration Nginx). Voir ma réponse pour une solution qui gère les échappements de barre oblique inverse.<<"EOF"
, qui n'interpole pas les variables (les terminateurs entre guillemets sont comme les guillemets simples d'heredocs).cat template.txt | envsubst
envsubst était nouveau pour moi. Fantastique.
Pour mémoire, l'utilisation d'un heredoc est un excellent moyen de modéliser un fichier de configuration.
la source
envsubst
parce que cela m'a sauvé de l'additionapt-get install gettext-base
dans mon DockerfileJe suis d'accord avec l'utilisation de sed: c'est le meilleur outil de recherche / remplacement. Voici mon approche:
la source
-i
option (modifier les fichiers en place) qui est similaire à l' option perl . Consultez la page de manuel de votre sed .Je pense qu'eval fonctionne vraiment bien. Il gère les modèles avec des sauts de ligne, des espaces et toutes sortes de choses bash. Si vous avez un contrôle total sur les modèles eux-mêmes, bien sûr:
Cette méthode doit être utilisée avec précaution, bien sûr, car eval peut exécuter du code arbitraire. Exécuter ceci en tant que root est quasiment hors de question. Les citations du modèle doivent être échappées, sinon elles seront mangées par
eval
.Vous pouvez également utiliser ici des documents si vous préférez
cat
àecho
@plockc a proposé une solution qui évite le problème d'échappatoire des citations bash:
Éditer: Suppression de la partie sur l'exécution de ceci en tant que root en utilisant sudo ...
Edit: Ajout d'un commentaire sur la façon dont les citations doivent être échappées, ajout de la solution de plockc au mix!
la source
eval
éditionecho
/cat
commande des processus eux; essayezeval "echo \"'\$HOME'\""
.J'ai une solution bash comme mogsie mais avec heredoc au lieu de herestring pour vous permettre d'éviter d'échapper des guillemets doubles
la source
${param:?}
un texte d'imbrication autour de paramètres optionnels. Exemple: se${DELAY:+<delay>$DELAY</delay>}
développe en rien lorsque DELAY n'est pas défini et <delay> 17 </delay> lorsque DELAY = 17._EOF_$$
.$trailing_newline
, ou d'utiliser$NL5
et de s'assurer qu'elle est développée en 5 nouvelles lignes.template.txt
fonctionnerait afin de préserver les nouvelles lignes de fin.eval
, iftemplate.txt
containsEOF
sur une ligne propre, il terminera prématurément l'ici-doc et interrompra ainsi la commande. (Pointe du chapeau à @xebeche).Edit 6 janvier 2017
J'avais besoin de garder des guillemets doubles dans mon fichier de configuration, donc les doubles guillemets d'échappement avec sed aident:
Je ne peux pas penser à garder de nouvelles lignes à la fin, mais les lignes vides entre les deux sont conservées.
Bien que ce soit un vieux sujet, l'OMI j'ai trouvé une solution plus élégante ici: http://pempek.net/articles/2013/07/08/bash-sh-as-template-engine/
Tous les crédits à Grégory Pakosz .
la source
eval "echo \"$(sed 's/\"/\\"/g' $1)\""
$variables
).Au lieu de réinventer la roue, allez avec envsubst Peut être utilisé dans presque tous les scénarios, par exemple la création de fichiers de configuration à partir de variables d'environnement dans des conteneurs de docker.
Si sur mac, assurez-vous d'avoir un homebrew, puis liez-le à partir de gettext:
./template.cfg
./.env:
./configure.sh
Maintenant, utilisez-le simplement:
la source
envsubst
fonctionne réellement.envsubst
ne fonctionne pas sur Mac OS, vous auriez besoin de l' installer à l' aide homebrew:brew install gettext
.Une version plus longue mais plus robuste de la réponse acceptée:
Cela étend toutes les instances de
$VAR
ou${VAR}
à leurs valeurs d'environnement (ou, si elles ne sont pas définies, la chaîne vide).Il échappe correctement les contre-obliques et accepte un $ échappé par une barre oblique inverse pour empêcher la substitution (contrairement à envsubst, qui, en fait, ne fait pas cela ).
Donc, si votre environnement est:
et votre modèle est:
le résultat serait:
Si vous souhaitez uniquement échapper les contre-obliques avant $ (vous pouvez écrire "C: \ Windows \ System32" dans un modèle inchangé), utilisez cette version légèrement modifiée:
la source
Je l'aurais fait de cette façon, probablement moins efficace, mais plus facile à lire / maintenir.
la source
sed -e 's/VARONE/NEWVALA/g' -e 's/VARTWO/NEWVALB/g' -e 's/VARTHR/NEWVALC/g' < $TEMPLATE > $OUTPUT
Si vous souhaitez utiliser des modèles Jinja2 , consultez ce projet: j2cli .
Elle supporte:
la source
En prenant la réponse de ZyX en utilisant pure bash mais avec une nouvelle correspondance de regex de style et une substitution indirecte de paramètres, cela devient:
la source
Si l'utilisation de Perl est une option et que vous vous contentez de baser les extensions sur des variables d' environnement uniquement (par opposition à toutes les variables shell ), considérez la réponse robuste de Stuart P. Bentley .
Cette réponse vise à fournir une solution uniquement bash qui, malgré son utilisation
eval
, devrait être sûre à utiliser .Les objectifs sont:
${name}
et$name
des références variables.$(...)
et syntaxe héritée`...`
)$((...))
et syntaxe héritée$[...]
).\
(\${name}
)."
et les\
instances.Fonction
expandVars()
:Exemples:
${HOME:0:10}
, tant qu'elles ne contiennent pas de commande intégrée ou de substitutions arithmétiques, telles que${HOME:0:$(echo 10)}
$(
et`
sont aveuglément échappées).${HOME
(fermeture manquante}
) BREAK la fonction.\$name
empêche l'expansion.\
non suivi de$
est conservé tel quel.\
instances adjacentes , vous devez les doubler ; par exemple:\\
->\
- le même que juste\
\\\\
->\\
0x1
,0x2
,0x3
.eval
.Si vous recherchez une solution plus restrictive qui ne prend en charge que les
${name}
extensions - c'est-à-dire, avec des accolades obligatoires , en ignorant les$name
références - voyez cette réponse .Voici une version améliorée de la
eval
solution bash-only, -free à partir de la réponse acceptée :Les améliorations sont:
${name}
et$name
des références variables.\
charge des références de variables -escaping qui ne devraient pas être développées.eval
solution basée ci-dessus,la source
Voici une autre solution pure bash:
$ cat code
$ cat template
(avec retours à la ligne et guillemets doubles)production
la source
Voici une autre solution: générer un script bash avec toutes les variables et le contenu du fichier modèle, ce script ressemblerait à ceci:
Si nous alimentons ce script dans bash, il produirait la sortie souhaitée:
Voici comment générer ce script et alimenter ce script dans bash:
Discussion
cat
commande avec HEREDOCSi vous souhaitez rediriger cette sortie dans un fichier, remplacez la dernière ligne par:
la source
Cette page décrit une réponse avec awk
la source
Cas parfait pour shtpl . (projet de la mienne, donc il n'est pas largement utilisé et manque de documentation. Mais voici la solution qu'il offre quand même. Pouvez-vous la tester.)
Exécutez simplement:
Le résultat est:
S'amuser.
la source
Il s'agit de la fonction pure bash ajustable à votre goût, utilisée en production et qui ne doit s'arrêter sur aucune entrée. Si ça casse - faites le moi savoir.
la source
Vous pouvez également utiliser bashible (qui utilise en interne l'approche d'évaluation décrite ci-dessus / ci-dessous).
Il y a un exemple, comment générer un HTML à partir de plusieurs parties:
https://github.com/mig1984/bashible/tree/master/examples/templates
la source
Voici une fonction bash qui préserve les espaces:
la source
Voici un
perl
script modifié basé sur quelques-unes des autres réponses:Fonctionnalités (basées sur mes besoins, mais devraient être faciles à modifier):
la source
Regardez le script python de substitution de variables simples ici: https://github.com/jeckep/vsubst
C'est très simple à utiliser:
la source
Pour suivre la réponse de plockc sur cette page, voici une version adaptée au tableau de bord, pour ceux d'entre vous qui cherchent à éviter les bashismes.
la source
Rien de plus simple que:
$ person = Bob ./render template.txt> rendu.txt
Voir https://github.com/relaxdiego/renderest
la source