web-dev-qa-db-fra.com

Comment passer une variable contenant des barres obliques à sed

Comment passez-vous une variable contenant des barres obliques en tant que modèle à sed?

Par exemple, si j'ai la variable suivante:

var="/Users/Documents/name/file"

Je veux le transmettre à sed comme suit:

sed "s/$var/replace/g" "$file"

Cependant je reçois des erreurs. Comment puis-je contourner le problème?

65
Bolboa

Utilisez un autre délimiteur de regex car sed vous permet d'utiliser n'importe quel délimiteur ( y compris les caractères de contrôle ):

sed "s~$var~replace~g" $file
118
anubhava

Une réponse purement bash: utilisez paramètre de développement pour supprimer les barres obliques inverses de la variable

var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file
38
glenn jackman

Une autre façon de le faire, bien que plus moche que la réponse d’anubhava, est d’éviter toutes les barres obliques inverses de var en utilisant une autre commande sed:

var=$(echo "$var" | sed 's/\//\\\//g')

alors, cela fonctionnera:

sed "s/$var/replace/g" $file
25
Bolboa

L'utilisation de / dans sed comme délimiteur entrera en conflit avec les barres obliques de la variable lors de la substitution, ce qui entraînera une erreur. Une façon de contourner ce problème consiste à utiliser un autre séparateur unique parmi tous les caractères de cette variable.

var="/Users/Documents/name/file"

vous pouvez utiliser le caractère octothorpe qui convient à l'occasion (ou tout autre caractère qui n'est pas un / pour la facilité d'utilisation)

sed "s#$var#replace#g" 

ou 

  sed 's#$'$var'#replace#g'

cela convient lorsque la variable ne contient pas d'espaces

ou

sed 's#$"'$var'"#replace#g'

Il est plus sage d'utiliser ce qui précède, car nous souhaitons substituer tout ce qui se trouve dans cette variable par rapport à la citation double de la commande entière, ce qui peut amener votre Shell à intercepter tout caractère qui pourrait être considéré comme un caractère spécial du Shell.

7
repzero

C'est une vieille question, mais aucune des réponses ici ne décrit en détail des opérations autres que s/from/to/.

La forme générale d'une instruction sed est

*address* *action*

adresse peut être une plage d'expression régulière ou une plage de numéros de lignes (ou vide, auquel cas la action est appliquée à chaque ligne d'entrée). Donc par exemple

sed '1,4d' file

supprime les lignes 1 à 4 (la adresse est la plage de numéros de lignes 1,4 et la action est la commande d delete); et

sed '/ick/,$s/foo/bar/' file

remplacera la première occurrence de foo par bar sur une ligne quelconque entre la première correspondance de l'expression régulière ick et la fin du fichier (la adresse est la plage /ick/,$ et la action est la commande de substitution ss/foo/bar/ ).

Dans ce contexte, si ick provenait d'une variable, vous pourriez faire

sed "/$variable/,\$s/foo/bar/"

(notez l'utilisation de guillemets doubles au lieu de simples, afin que le shell puisse interpoler la variable et la nécessité de mettre le signe dollar littéral entre guillemets), mais si la variable contient une barre oblique, vous obtiendrez une erreur de syntaxe. (Le shell développe la variable, puis passe la chaîne résultante à sed; donc, sed ne voit que le texte littéral - il n’a aucune notion des variables du shell.)

Le remède consiste à utiliser un délimiteur différent (où vous devez évidemment pouvoir utiliser un caractère qui ne peut pas figurer dans la valeur de la variable), mais contrairement au cas s%foo%bar%, vous avez également besoin d'une barre oblique inverse avant le délimiteur si vous souhaitez utiliser un caractère différent. Délimiteur différent de celui par défaut /:

sed "\\%$variable%,\$s/foo/bar/" file

(entre guillemets simples, une simple barre oblique inverse suffirait évidemment); ou vous pouvez échapper séparément chaque barre oblique de la valeur. Cette syntaxe particulière est Bash uniquement:

sed "/${variable//\//\\/}/,\$s/foo/bar/" file

ou si vous utilisez un autre shell, essayez

escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file

Pour plus de clarté, si $variable contenait la chaîne 1/2, les commandes ci-dessus seraient équivalentes à

sed '\%1/2%,$s/foo/bar/' file

dans le premier cas, et

sed '/1\/2/,$s/foo/bar/' file

dans la seconde.

3
tripleee

Utilisez Perl, où les variables sont des citoyens de première classe, pas seulement des macros extensibles:

var=/Users/Documents/name/file Perl -pe 's/\Q$ENV{var}/replace/g' $file
  • -p lit ligne par ligne et imprime la ligne après traitement
  • \Q cite tous les métacaractères de la chaîne suivante (inutile pour la valeur présentée ici, mais nécessaire si la valeur contenait [ ou une autre valeur spéciale pour les expressions régulières)
0
choroba