Existe-t-il une liste complète des personnages qui doivent être échappés dans Bash? Peut-il être vérifié uniquement avec sed
?
En particulier, je vérifiais s'il %
fallait échapper ou non. j'ai essayé
echo "h%h" | sed 's/%/i/g'
et a bien fonctionné, sans s'échapper %
. Cela signifie-t-il qu'il %
ne faut pas s'échapper? Était-ce un bon moyen de vérifier la nécessité?
Et plus généralement: sont-ils les mêmes personnages pour s'échapper dans shell
et bash
?
Réponses:
Il existe deux règles simples et sûres qui fonctionnent non seulement dans
sh
mais aussibash
.1. Mettez la chaîne entière entre guillemets simples
Cela fonctionne pour tous les caractères, sauf les guillemets simples. Pour échapper au guillemet simple, fermez le guillemet avant, insérez le guillemet simple et rouvrez le guillemet.
commande sed:
sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"
2. Échapper à tous les caractères avec une barre oblique inverse
Cela fonctionne pour tous les personnages sauf le saut de ligne. Pour les caractères de nouvelle ligne, utilisez des guillemets simples ou doubles. Les chaînes vides doivent toujours être traitées - remplacer par
""
commande sed:
sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
.2b. Version plus lisible de 2
Il y a un jeu de caractères sûr et facile, comme
[a-zA-Z0-9,._+:@%/-]
, qui peut être laissé sans échappement pour le rendre plus lisiblecommande sed:
LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
.Notez que dans un programme sed, on ne peut pas savoir si la dernière ligne d'entrée se termine par un octet de nouvelle ligne (sauf lorsqu'il est vide). C'est pourquoi les deux commandes sed ci-dessus supposent que non. Vous pouvez ajouter manuellement une nouvelle ligne entre guillemets.
Notez que les variables shell ne sont définies que pour le texte au sens POSIX. Le traitement des données binaires n'est pas défini. Pour les implémentations importantes, le binaire fonctionne à l'exception des octets NUL (car les variables sont implémentées avec des chaînes C et destinées à être utilisées comme des chaînes C, à savoir des arguments de programme), mais vous devez passer à un environnement local "binaire" tel que latin1 .
(Vous pouvez facilement valider les règles en lisant la spécification POSIX pour
sh
. Pour bash, consultez le manuel de référence lié par @AustinPhillips)la source
sed
, mais nécessitebash
.format qui peut être réutilisé comme entrée shell
Il existe une directive de format spécial
printf
(%q
) conçue pour ce type de demande:Certains échantillons:
Cela pourrait également être utilisé par le biais de variables:
Vérification rapide avec tous les (128) octets ascii:
Notez que tous les octets de 128 à 255 doivent être échappés.
Cela doit rendre quelque chose comme:
Où le premier champ est la valeur hexa de l'octet, le second contient
E
si le caractère doit être échappé et le troisième champ affiche la présentation échappée du caractère.Pourquoi
,
?Vous pouvez voir des personnages qui ne sont pas toujours besoin d'être échappé, comme
,
,}
et{
.Donc pas toujours mais parfois :
ou
mais attention:
la source
subprocess.Popen(['bash', '-c', 'printf "%q\0" "$@"', '_', arbitrary_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()
vous donnera une version correctement citée de shellarbitrary_string
.%q
été brisé pendant longtemps - Si mon esprit me sert bien, une erreur a été corrigée (mais pourrait encore être brisée) en 2013 après avoir été brisée pendant environ 10 ans. Alors ne vous y fiez pas.shlex.quote()
(> = 3.3,pipes.quote()
- non documenté - pour les anciennes versions) fera également le travail et produira une version plus lisible par l'homme (en ajoutant des guillemets et en s'échappant, si nécessaire) de la plupart des chaînes, sans avoir besoin de faire apparaître un obus.,
. J'ai été surpris d'apprendre que Bash intégréprintf -- %q ','
donne\,
, mais/usr/bin/printf -- %q ','
donne,
(non échappé). Idem pour d' autres caractères:{
,|
,}
,~
.Pour éviter à quelqu'un d'autre d'avoir à RTFM ... en bash :
... donc si vous y échappez (et la citation elle-même, bien sûr), vous êtes probablement d'accord.
Si vous adoptez une approche plus conservatrice «en cas de doute, échappez-vous à lui», il devrait être possible d'éviter à la place d'obtenir des caractères ayant une signification spéciale en n'échappant pas aux caractères d'identification (c.-à-d. Lettres ASCII, chiffres ou «_»). Il est très peu probable que ceux-ci aient jamais (c'est-à-dire dans un shell POSIX-ish étrange) une signification particulière et doivent donc être échappés.
la source
En utilisant la
print '%q'
technique , nous pouvons exécuter une boucle pour découvrir quels caractères sont spéciaux:Il donne cette sortie:
Certains des résultats, comme l'
,
air un peu suspect. Il serait intéressant d'obtenir les contributions de @ CharlesDuffy à ce sujet.la source
,
air un peu suspect au dernier paragraphe de ma réponse%q
ne savez pas où vous envisagez d'utiliser le personnage dans le shell, il échappera donc à tous les personnages qui peuvent avoir une signification particulière dans n'importe quel contexte de shell possible.,
elle-même n'a pas de signification particulière pour elle, mais comme @ F.Hauri l'a souligné dans sa réponse, elle a une signification particulière dans l'{...}
expansion de l'accolade: gnu.org/savannah-checkouts/gnu/bash/manual/… C'est comme! qui ne nécessite également une expansion que dans des situations spécifiques, pas en général:echo Hello World!
fonctionne très bien, maisecho test!test
échouera.Les caractères qui doivent s'échapper sont différents dans Bourne ou dans le shell POSIX que dans Bash. Généralement (très) Bash est un sur-ensemble de ces obus, donc tout ce que vous échappez
shell
doit être échappé dans Bash.Une belle règle générale serait "en cas de doute, échappez-vous". Mais échapper à certains personnages leur donne une signification particulière, comme
\n
. Ceux-ci sont répertoriés dans lesman bash
pages sousQuoting
etecho
.A part ça, échappez à tout caractère qui n'est pas alphanumérique, c'est plus sûr. Je ne connais pas de liste définitive.
Les pages de manuel les répertorient toutes quelque part, mais pas au même endroit. Apprenez la langue, c'est le moyen d'en être sûr.
Celui qui m'a rattrapé est
!
. Il s'agit d'un caractère spécial (extension historique) dans Bash (et csh) mais pas dans le shell Korn.echo "Hello world!"
Donne même des problèmes. L'utilisation de guillemets simples, comme d'habitude, supprime la signification spéciale.la source
sed
est suffisant pour voir s'il doit être échappé. Merci pour votre réponse!sed
n'est pas nécessaire, vous pouvez vérifier avec presque n'importe quoi.sed
n'est pas le problème,bash
est. À l'intérieur des guillemets simples, il n'y a pas de caractères spéciaux (sauf les guillemets simples), vous ne pouvez même pas y échapper. Unesed
commande doit généralement se trouver entre guillemets simples car les métacaractères RE ont trop de chevauchements avec les métacaractères shell pour être sûrs. L'exception est lors de l'incorporation de variables shell, ce qui doit être fait avec soin.echo
. Si vous sortez ce que vous avez mis, il n'a pas besoin d'être échappé. :)Je suppose que vous parlez de chaînes bash. Il existe différents types de chaînes qui ont un ensemble d'exigences différent pour l'échappement. par exemple. Les chaînes de guillemets simples sont différentes des chaînes entre guillemets doubles.
La meilleure référence est la Citant section du manuel bash.
Il explique quels personnages doivent s'échapper. Notez que certains caractères peuvent nécessiter un échappement selon les options activées telles que l'expansion de l'historique.
la source
J'ai remarqué que bash échappe automatiquement certains caractères lors de l'utilisation de la saisie semi-automatique.
Par exemple, si vous avez un répertoire nommé
dir:A
, bash se complétera automatiquement pourdir\:A
En utilisant cela, j'ai exécuté quelques expériences en utilisant des caractères de la table ASCII et dérivé les listes suivantes:
Caractères que bash échappe lors de la saisie semi-automatique : (inclut l'espace)
Les personnages que bash n'échappe pas :
(J'ai exclu
/
, car il ne peut pas être utilisé dans les noms de répertoire)la source
printf %q
modifient et ne modifient pas s'ils sont passés en argument - idéalement, en parcourant l'ensemble du jeu de caractères.