web-dev-qa-db-fra.com

Comment substituer des variables Shell dans des fichiers texte complexes

J'ai plusieurs fichiers texte dans lesquels j'ai introduit des variables Shell ($ VAR1 ou $ VAR2 par exemple).

Je voudrais prendre ces fichiers (un par un) et les sauvegarder dans de nouveaux fichiers où toutes les variables auraient été remplacées.

Pour ce faire, j'ai utilisé le script Shell suivant (présent sur StackOverflow):

while read line
do
    eval echo "$line" >> destination.txt
done < "source.txt"

Cela fonctionne très bien sur des fichiers très basiques.

Mais sur des fichiers plus complexes, la commande "eval" en fait trop:

  • Les lignes commençant par "#" sont ignorées

  • L'analyse des fichiers XML génère des tonnes d'erreurs

Y a-t-il une meilleure façon de le faire? (en script shell ... je sais que cela se fait facilement avec Ant par exemple)

Sincères amitiés

46
Ben

En regardant, il se trouve que sur mon système, il existe une commande envsubst qui fait partie du paquet gettext-base. 

Donc, cela facilite les choses: 

envsubst < "source.txt" > "destination.txt"
118
derobert

En vous référant à la réponse 2, lors de la discussion sur envsubst, vous avez demandé "Comment puis-je le faire fonctionner avec les variables déclarées dans mon script .sh?"

La réponse est que vous devez simplement exporter vos variables avant d'appeler envsubst.

Vous pouvez également limiter les chaînes de variables que vous souhaitez remplacer dans l'entrée à l'aide de l'argument envsubst Shell_FORMAT (en évitant le remplacement involontaire d'une chaîne dans l'entrée par une valeur de variable Shell commune, par exemple $ HOME).

Par exemple:

export VAR1='somevalue' VAR2='someothervalue'
MYVARS='$VAR1:$VAR2'

envsubst "$MYVARS" <source.txt >destination.txt

Remplacera toutes les occurrences de $ VAR1 et $ VAR2 (et uniquement VAR1 et VAR2) dans source.txt par 'somevalue' et 'someothervalue' respectivement.

44
Michael

Je sais que ce sujet est ancien, mais j’ai une solution de travail plus simple sans exporter les variables. Peut-être un oneliner, mais je préfère diviser en utilisant \ à la fin de la ligne.

var1='myVar1'\
var2=2\
var3=${var1}\
envsubst '$var1,$var3' < "source.txt" > "destination.txt"

#         ^^^^^^^^^^^    ^^^^^^^^^^     ^^^^^^^^^^^^^^^
# define which to replace   input            output

Les variables doivent être définies sur la même ligne que envsubst afin d’être considérées comme des variables d’environnement.

Le '$var1,$var3' est facultatif pour ne remplacer que ceux spécifiés. Imaginez un fichier d’entrée contenant ${VARIABLE_USED_BY_JENKINS} qui ne devrait pas être remplacé.

6
inetphantom
  1. Définir votre variable ENV
$ export MY_ENV_VAR=congratulation
  1. Créer un fichier modèle ( in.txt ) avec le contenu suivant
$MY_ENV_VAR

Vous pouvez également utiliser toutes les autres variables ENV définies par votre système comme (sous linux) $ TERM, $ Shell, $ HOME ...

  1. Exécutez cette commande pour remplacer toutes les variables d’environnement dans votre fichier in.txt et écrire le résultat dans out.txt
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
  1. Vérifier le contenu du fichier out.txt
$ cat out.txt

et vous devriez voir "félicitation".

3
Dado

envsubst semble exactement comme quelque chose que je voulais utiliser, mais l'option -v m'a un peu surpris.

Alors que envsubst < template.txt fonctionnait bien, la même chose avec l'option -v ne fonctionnait pas:

$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.1 (Maipo)
$ envsubst -V
envsubst (GNU gettext-runtime) 0.18.2
Copyright (C) 2003-2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Bruno Haible.

Comme je l'ai écrit, cela ne fonctionnait pas:

$ envsubst -v < template.txt
envsubst: missing arguments
$ cat template.txt | envsubst -v
envsubst: missing arguments

Je devais le faire pour que cela fonctionne:

TEXT=`cat template.txt`; envsubst -v "$TEXT"

Peut-être que ça aide quelqu'un.

0
Betlista

Si vous voulez vraiment uniquement utiliser bash (et sed), alors je passerai en revue chacune de vos variables d'environnement (retournées par set en mode posix) et créerai un groupe de -e 'regex' pour celui-ci, terminé par un -e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g', puis passerai tout ça pour sed.

Perl ferait un travail plus agréable, cependant, vous avez accès aux vars d’environnement en tant que tableau et vous pouvez effectuer des remplacements exécutables de sorte que vous ne correspondiez qu’à une seule variable d’environnement.

0
w00t

En fait, vous devez changer votre read en read -r, ce qui le fera ignorer les barres obliques inverses.

En outre, vous devriez échapper les guillemets et les barres obliques inverses .

while read -r line; do
  line="${line//\\/\\\\}"
  line="${line//\"/\\\"}"
  line="${line//\`/\\\`}"
  eval echo "\"$line\""
done > destination.txt < source.txt

Encore une façon terrible de faire de l’expansion.

0
w00t