De quels caractères dois-je m'échapper lors de l'utilisation de sed dans un script sh?

Prenez le script suivant:

#!/bin/sh sed 's/(127\.0\.1\.1)\s/\1/' [some file] 

Si j'essaie d'exécuter ceci dans sh ( dash ici), cela va échouer à cause des parenthèses, qui doivent être échappées. Mais je n'ai pas besoin d'échapper aux backslashes eux-mêmes (entre les octets, ou dans le \s ou \1 ). Quelle est la règle ici? Qu'en est-il quand je dois utiliser {...} ou [...] ? Y a-t-il une list de ce que je fais et n'ai pas besoin de m'échapper?

Il y a deux niveaux d'interprétation ici: le shell, et sed.

Dans le shell, tout ce qui se trouve entre guillemets simples est interprété littéralement, à l'exception des guillemets simples eux-mêmes. Vous pouvez effectivement avoir une seule guillemets entre guillemets simples en écrivant '\'' (guillemet simple fermé, guillemet simple littéral, guillemet simple ouvert).

Sed utilise des expressions régulières de base . Dans un BRE, les caractères $.*[\]^ Doivent être précédés d'une barre oblique inverse, sauf dans les jeux de caractères ( […] ). Lettres, numbers et (){}+?| ne doit pas être cité (vous pouvez vous en passer en citant certaines de ces implémentations). Les suites \( , \) , \n et dans certaines implémentations \{ , \} , \+ , \? , \| et d'autres barres obliques inverses + caractères alphanumériques ont des significations particulières. Vous pouvez vous en sortir sans citer $^] dans certaines positions de certaines implémentations.

En outre, vous avez besoin d'une barre oblique inverse avant / si elle doit apparaître dans la regex. Vous pouvez choisir un autre caractère comme délimiteur en écrivant par exemple s~/dir~/replacement~ ou \~/dir~p ; vous aurez besoin d'une barre oblique inverse avant le délimiteur si vous souhaitez l'inclure dans le BRE. Si vous choisissez un caractère qui a une signification particulière dans un BRE et que vous voulez l'inclure littéralement, vous aurez besoin de trois barres obliques inverses; Je ne recommand pas cela.

En résumé, pour sed 's/…/…/' :

  • Écrivez l'expression rationnelle entre guillemets simples.
  • Utilisez '\'' pour finir avec un guillemet simple dans l'expression rationnelle.
  • Mettez une barre oblique inverse avant $.*/[\]^ Et seulement ces caractères.

Dans le text de rlocation:

  • & et \ besoin d'être cité, de même que le délimiteur (habituellement / ) et les returns à la ligne.
  • \ suivi d'un chiffre a une signification particulière. \ suivi d'une lettre a une signification spéciale (caractères spéciaux) dans certaines implémentations, et \ suivi d'un autre caractère signifie \c ou c selon l'implémentation.
  • Avec des guillemets simples autour de l'argument ( sed 's/…/…/' ), utilisez '\'' pour mettre un guillemet simple dans le text de rlocation.

Si le text regex ou de rlocation provient d'une variable shell, callbackez-vous que

  • l'expression rationnelle est un BRE, pas une string littérale;
  • dans l'expression rationnelle, une nouvelle ligne doit être exprimée par \n ;
  • dans le text de rlocation, & , \ et les returns doivent être cités;
  • le délimiteur doit être cité.
  • Utilisez des guillemets doubles pour l'interpolation: sed -e "s/$BRE/$REPL/"

Le problème que vous rencontrez n'est pas dû à l'interpolation de shell et aux évasements – c'est parce que vous essayez d'utiliser la syntaxe d'expression régulière étendue sans passer l'option -r ou --regexp-extended .

Changez votre ligne sed de

 sed 's/(127\.0\.1\.1)\s/\1/' [some file] 

à

 sed -r 's/(127\.0\.1\.1)\s/\1/' [some file] 

et cela fonctionnera comme je crois que vous avez l'intention.

Par défaut sed utilise des expressions régulières de base (pensez au style grep), ce qui nécessiterait la syntaxe suivante:

 sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file] 

À less que vous vouliez interpoler une variable shell dans l'expression sed, utilisez des guillemets simples pour l'expression entière car ils font que tout ce qui se trouve entre eux est interprété tel quel, y compris les barres obliques inversées.

Donc, si vous voulez sed voir s/\(127\.0\.1\.1\)\s/\1/ mettre des guillemets autour et le shell ne touchera pas les parenthèses ou les antislashs. Si vous avez besoin d'interpoler une variable shell, mettez uniquement cette partie entre guillemets doubles. Par exemple

 sed 's/\(127\.0\.1\.1\)/'"$ip"'/' 

Cela vous évitera de vous callbacker quels métacaractères de shell ne sont pas échappés par des guillemets doubles.