Affectation d’une valeur ayant un point-virgule (‘;’) à une variable dans bash

J’essaie d’échapper (‘\’) à un point-virgule (‘;’) dans une chaîne sur un shell unix (bash) avec sed. Cela fonctionne quand je le fais directement sans assigner la valeur à une variable. C’est,

$ echo "hello;" | sed 's/\([^\\]\);/\1\\;/g' hello\; $ 

Cependant, il ne semble pas fonctionner lorsque la commande ci-dessus est assignée à une variable:

 $ result=`echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'` $ $ echo $result hello; $ 

Une idée pourquoi?

J’ai essayé en utilisant la valeur avec et sans guillemets mais cela n’a pas aidé. Tout indice grandement apprécié.

btw, j’ai d’abord pensé que le point-virgule à la fin de la chaîne faisait en quelque sorte office de terminateur et que le shell ne continuait donc pas à exécuter le sed (si cela avait du sens). Cependant, cela ne semble pas être un problème. J’ai essayé en utilisant le point-virgule pas à la fin de la chaîne (quelque part entre les deux). Je vois toujours le même résultat qu’auparavant. C’est,

 $ echo "hel;lo" | sed 's/\([^\\]\);/\1\\;/g' hel\;lo $ $ result=`echo "hel;lo" | sed 's/\([^\\]\);/\1\\;/g'` $ $ echo $result hel;lo $ 

Je trouve intéressant que l’utilisation de back-ticks donne un résultat (votre résultat) et l’utilisation de $(...) donne un autre résultat (le résultat recherché):

 $ echo "hello;" | sed 's/\([^\\]\);/\1\\;/g' hello\; $ z1=$(echo "hello;" | sed 's/\([^\\]\);/\1\\;/g') $ z2=`echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'` $ printf "%s\n" "$z1" "$z2" hello\; hello; $ 

Si jamais vous aviez besoin d’un argument pour utiliser la notation moderne x=$(...) de préférence à l’ancienne notation x=`...` , c’est probablement le cas. Le shell effectue une série d’interprétations supplémentaires avec les back-ticks. Je peux le démontrer avec un petit programme que j’utilise lors du débogage de scripts shell appelés al (pour ‘argument list’); vous pouvez le simuler avec printf "%s\n" :

 $ z2=`echo "hello;" | al sed 's/\([^\\]\);/\1\\;/g'` $ echo "$z2" sed s/\([^\]\);/\1\;/g $ z1=$(echo "hello;" | al sed 's/\([^\\]\);/\1\\;/g') $ echo "$z1" sed s/\([^\\]\);/\1\\;/g $ z1=$(echo "hello;" | printf "%s\n" sed 's/\([^\\]\);/\1\\;/g') $ echo "$z1" sed s/\([^\\]\);/\1\\;/g $ 

Comme vous pouvez le voir, le script exécuté par sed diffère selon que vous utilisez la notation x=$(...) ou la notation x=`...` .

 s/\([^\]\);/\1\;/g # `` s/\([^\\]\);/\1\\;/g # $() 

Résumé

Utilisez $(...) ; c’est plus facile à comprendre.

Vous n’avez pas besoin de sed (ou de tout autre moteur regex) pour cela:

 s='hello;' echo "${s//;/\;}" 

Ceci est une extension de paramètre qui remplace ; avec \; .

Cela dit – pourquoi essayez-vous de le faire? Dans la plupart des cas, vous ne voulez pas que les caractères d’échappement (qui sont la syntaxe) soient à l’intérieur de variables scalaires (qui sont des données); elles sont importantes uniquement si vous parsingz vos données en tant que syntaxe (par exemple, en utilisant eval), ce qui est une mauvaise idée pour d’autres raisons, et il vaut mieux les éviter (ou les programmer, comme via printf %q ).

Vous devez utiliser quatre (trois fonctionnent également). Je suppose que c’est parce qu’il est interprété deux fois, le premier par la commande sed et le second par le shell lors de la lecture du contenu de la variable:

 result=`echo "hello;" | sed 's/\([^\\]\);/\1\\\\;/g'` 

Et

 echo "$result" 

donne:

 hello\;