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?
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
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
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
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.
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*
où 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 s
s/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.
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)