Prenez le script suivant:
#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]
Si j'essaie d'exécuter ceci sh
( dash
ici), cela échouera à cause des parenthèses, qui doivent être évitées. Mais je n'ai pas besoin d'échapper aux barres obliques inverses elles-mêmes (entre les octets, ou dans le \s
ou \1
). Quelle est la règle ici? Qu'en est-il quand j'ai besoin d'utiliser {...}
ou [...]
? Existe-t-il une liste de ce que je fais et n'ai pas besoin de m'échapper?
shell-script
sed
quoting
vraiment
la source
la source
function sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
Réponses:
Il y a deux niveaux d'interprétation ici: la coquille 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 un seul devis entre guillemets simples en écrivant
'\''
(fermez un seul devis, un seul devis littéral, ouvrez un seul devis).Sed utilise des expressions régulières de base . Dans un BRE, pour les traiter littéralement, vous
$.*[\^
devez les citer en les faisant précéder d'une barre oblique inverse, sauf dans les jeux de caractères ([…]
). Les lettres, les chiffres et(){}+?|
ne doivent pas être cités (vous pouvez vous en tenir à certaines de ces implémentations). Les séquences\(
,\)
,\n
, et , dans certaines mises en œuvre\{
,\}
,\+
,\?
,\|
et d' autres caractères alphanumériques + barre oblique inverse ont une signification particulière. Vous pouvez vous en tirer en ne citant pas$^
certaines positions dans certaines implémentations.De plus, vous avez besoin d'une barre oblique inverse avant
/
si elle doit apparaître dans l'expression rationnelle en dehors des expressions entre crochets. Vous pouvez choisir un autre caractère comme séparateur 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 souhaitez l'inclure littéralement, vous aurez besoin de trois barres obliques inverses. Je ne le recommande pas, car cela peut se comporter différemment dans certaines implémentations.En un mot, pour
sed 's/…/…/'
:'\''
pour finir avec une seule citation dans la regex.$.*/[\]^
et uniquement ces caractères (mais pas à l'intérieur des expressions entre crochets). (Techniquement vous ne devriez pas mettre une barre oblique inverse avant]
mais je ne sais pas d'une mise en œuvre qui traite]
et\]
différemment en dehors des expressions du support.)-
être traité littéralement, assurez-vous qu’elle est première ou dernière ([abc-]
ou[-abc]
non).[a-bc]
^
être traité à la lettre, assurez-vous que ce n’est pas la première (utilisation[abc^]
, non).[^abc]
]
dans la liste des caractères mis en correspondance par une expression entre crochets,^
définissez- le comme premier (ou premier après pour un ensemble annulé):[]abc]
ou[^]abc]
(ni).[abc]]
nor[abc\]]
Dans le texte de remplacement:
&
et\
doivent être cités en les précédant par une barre oblique inverse, comme le font le délimiteur (généralement/
) et les nouvelles lignes.\
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\c
ou enc
fonction de l'implémentation.sed 's/…/…/'
), utilisez'\''
pour mettre un guillemet simple dans le texte de remplacement.Si le regex ou le texte de remplacement provient d'une variable shell, rappelez-vous que
\n
(ce qui ne correspondra jamais à moins que vous n'ayez un autresed
code ajoutant des caractères de nouvelle ligne à l'espace de modèle). Mais notez que cela ne fonctionnera pas dans les expressions entre crochets avec certainessed
implémentations.&
,\
et les nouvelles lignes doivent être citées.sed -e "s/$BRE/$REPL/"
.la source
\\*
). Exemple:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
Le problème que vous rencontrez n'est pas dû à l'interpolation ni aux échappements de shell, mais bien au fait que vous essayez d'utiliser la syntaxe d'expression régulière étendue sans transmettre l' option
-r
or--regexp-extended
.Changer votre ligne sed de
à
et cela fonctionnera comme je crois que vous avez l’intention.
Par défaut, sed utilise des expressions rationnelles de base (think grep style), qui nécessiteraient la syntaxe suivante:
la source
-r
comme option était ce qui était nécessaire dans mon cas.Sauf si vous souhaitez interpoler une variable shell dans l'expression sed, utilisez des guillemets simples pour l'expression entière, car ils font que tout ce qui les sépare est interprété tel quel, y compris les barres obliques inverses.
Donc, si vous voulez que sed puisse voir
s/\(127\.0\.1\.1\)\s/\1/
mettre des guillemets simples autour et que le shell ne touchera pas les parenthèses ou les barres obliques inverses. Si vous avez besoin d'interpoler une variable shell, mettez uniquement cette partie entre guillemets. Par exempleCela vous évitera de vous rappeler quels métacaractères de shell ne sont pas protégés par des guillemets doubles.
la source
sed
voirs/(127\.0\.1\.1)/...
, mais mettre cela dans un script shell tel quel ne fonctionne pas. Ce que vous dites à propos de la coquille ne touchant pas les parenthèses semble faux. J'ai modifié ma question pour élaborer.sed 's/(127\.0\.1\.1)/IP \1/'
échoue parce que sed a besoin de voir\(
et\)
pour la syntaxe de groupe, pas(
et)
.