jeudi 24 février 2022

Substitution de variables d'environnement

Il existe un utilitaire qui permet la substitution de variables d'environnement: il s'agit de envsubst. Franchement, je ne connaissais pas cet utilitaire jusqu'à ce que je me heurte au problème suivant: substitution de variables dans une commande sed, lorsque le script avec les instructions de sed est un fichier (voir article précédent)

Expérimentons cet utilitaire. Tout d'abord je crée des variables d'environnement (dans un terminal):

export var1=Titine var2=Toto var3=Riri

Le mot export est nécessaire ou sinon on crée des variables du shell.

Ensuite je lance l'utilitaire en tapant envsubst suivi d'un appui sur ENTER.

Le curseur n'est pas après l'invite de commande: le système attend une action de ma part car envsubst renvoie vers la sortie standard (stdout), après traitement, le texte qui lui est fourni en entrée. Et rien ne lui est fourni. 

Allons-y! L'entrée standard est dans notre cas le clavier.

Je tape le texte 

$var2 aime $var1

suivi de ENTER pour envoyer. Aussitôt le retour apparaît à l'écran:


Je peux continuer à procéder, puis terminer avec CTRL-D, ce qui ramène le curseur après l'invite de commande:


Ce que j'ai tapé à l'écran je peux aussi le mettre dans un fichier appelé avant et lancer la commande:

envsubst < avant



Ici l'entée standard n'est plus le clavier, elle a été redirigée vers le fichier avant qui contient

$var2 aime $var1

mais $var3 aime aussi $var1

Je peux aussi créer le fichier après comme ceci:

envsubst < avant > après

Rien n’apparaît à l'écran puisque la sorte standard a été redirigée vers le fichier après.

Je peux aussi indiquer quelles sont les variables à considérer:


Cette fois var3 est ignoré.
Les variables à traiter peuvent même se trouver au sein d'un texte (appelé shell-format si on se réfère à man envsubst):


Ce texte peut se trouver dans un fichier.
Si le fichier sf-file contient par exemple

$var1 joue avec $var2

$var1 va au restaurant


la commande

envsubst "$(cat sf-file)" < avant

donnera le résultat escompté:


Avec l'option -v, envsubst donne la liste des variables qui seront retenues suite à l'utilisation d'un shell-format. L'entrée standard est ignorée. 
Exemple:



Avec cette commande:

envsubst -v "$(env | grep '^var' | sed 's/^/\$/')"

seules seront retenues les variables définies au début de ce billet:



dimanche 13 février 2022

sed et substitution

 Je considère le fichier toto:

Je m'appelle Toto.

Je vais à l'école avec Tata

Nous allons à pied car ce n'est pas loin.

Elle m'aime et ça c'est cool!

Et oui Tata aime Toto et Toto aime Tata.

La vie est belle car Tata habite près de Toto.

Ils se voient tous les jours!


Je voudrais y remplacer Tata par Titine (les amours sont changeantes), ce qui peut se faire aisément (en linux, dans un terminal) avec la commande sed:

sed -n 's/Tata/Titine/gp' toto
Je vais à l'école avec Titine
Et oui Titine aime Toto et Toto aime Titine.
La vie est belle car Titine habite près de Toto.

L'option -n de la commande sed empêche l'impression automatique. Le flag g provoque le remplacement de Tata par Titine pour toutes les occurrences de Tata. Le flag p provoque l'impression des lignes modifiées.
Pour des explications plus complètes voir ici.
Un problème se pose si le nom de la nouvelle copine est dans une variable:

export var=Titine
sed -n 's/Tata/$var/gp' toto
Je vais à l'école avec $var
Et oui $var aime Toto et Toto aime $var.
La vie est belle car $var habite près de Toto.

La substitution ne s'effectue pas !
La solution est toute simple: il suffit d'entourer le script avec des guillemets:

sed -n "s/Tata/$var/gp" toto
Je vais à l'école avec Titine
Et oui Titine aime Toto et Toto aime Titine.
La vie est belle car Titine habite près de Toto.

Autre solution:

sed -n 's/Tata/'$var'/gp' toto
Je vais à l'école avec Titine
Et oui Titine aime Toto et Toto aime Titine.
La vie est belle car Titine habite près de Toto.

La substitution de variable n'est plus empêchée car la première zone ouverte avec un apostrophe est ensuite refermée avant la variable

Si la variable contient le caractère "/" qui sert de séparateur dans sed, ce caractère doit alors être échappé.
Exemple:

export var='Titine\/02'
sed -n "s/Tata/$var/gp" toto
Je vais à l'école avec Titine/02
Et oui Titine/02 aime Toto et Toto aime Titine/02.
La vie est belle car Titine/02 habite près de Toto.

Une autre possibilité est d'utiliser un autre séparateur:

export var=Titine/02
sed -n "s:Tata:$var:gp" toto
Je vais à l'école avec Titine/02
Et oui Titine/02 aime Toto et Toto aime Titine/02.
La vie est belle car Titine/02 habite près de Toto.

Il reste à traiter le cas où l'instruction sed se trouve dans un fichier script, que je vais appeler totofile.
Donc le fichier totofile contient:

s/Tata/$var/gp

Allons y

export var=Titine
sed -n -f totofile toto
Je vais à l'école avec $var
Et oui $var aime Toto et Toto aime $var.
La vie est belle car $var habite près de Toto.

La substitution ne s'effectue pas de nouveau !
La seule solution que j'ai trouvée consiste à utiliser envsubst:

export var=Titine
sed -n -f <(envsubst < totofile) toto
Je vais à l'école avec Titine
Et oui Titine aime Toto et Toto aime Titine.
La vie est belle car Titine habite près de Toto.