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.