web-dev-qa-db-fra.com

Quels personnages doivent être échappés lors de l'utilisation de Bash?

Existe-t-il une liste complète des caractères à échapper dans Bash? Peut-il être vérifié uniquement avec sed?

En particulier, je vérifiais si % devait ou non être échappé. j'ai essayé

echo "h%h" | sed 's/%/i/g'

et a bien fonctionné, sans échapper à %. Est-ce que cela signifie que % n'a pas besoin d'être échappé? Était-ce un bon moyen de vérifier la nécessité?

Et plus généralement: s'agit-il des mêmes personnages qui échappent dans Shell et bash?

159
fedorqui

Il existe deux règles simples et sûres qui fonctionnent non seulement dans sh, mais aussi bash.

1. Mettez la chaîne entière entre guillemets simples

Cela fonctionne pour tous les caractères sauf la citation simple elle-même. Pour échapper à la citation simple, fermez la citation la précédant, insérez-la et rouvrez-la.

'I'\''m a s@fe $tring which ends in newline
'

commande sed: sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"

2. Echappez chaque personnage avec une barre oblique inverse

Cela fonctionne pour tous les personnages sauf Newline. Pour les caractères de nouvelle ligne, utilisez des guillemets simples ou doubles. Les chaînes vides doivent toujours être traitées - remplacer par ""

\I\'\m\ \a\ \s\@\f\e\ \$\t\r\i\n\g\ \w\h\i\c\h\ \e\n\d\s\ \i\n\ \n\e\w\l\i\n\e"
"

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é tel quel pour le rendre plus lisible

I\'m\ a\ s@fe\ \$tring\ which\ ends\ in\ newline"
"

commande 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 s'il est vide). C'est pourquoi les deux commandes sed précédentes supposent que ce n'est pas le cas. Vous pouvez ajouter une nouvelle ligne citée manuellement.

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 qui importent, le binaire fonctionne à l'exception des octets NUL (car les variables sont implémentées avec des chaînes C et doivent être utilisées en tant que chaînes C, à savoir des arguments de programme), mais vous devez passer à un paramètre régional "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 associé à @AustinPhillips)

219
Jo So

format pouvant être réutilisé comme entrée Shell

Il y a une directive de formatage spécialprintf (%q) construite pour ce type de requête:

printf [-v var] format [arguments]

 %q     causes printf to output the corresponding argument
        in a format that can be reused as Shell input.

Certains échantillons:

read foo
Hello world
printf "%q\n" "$foo"
Hello\ world

printf "%q\n" $'Hello world!\n'
$'Hello world!\n'

Cela pourrait aussi être utilisé avec des variables:

printf -v var "%q" "$foo
"
echo "$var"
$'Hello world\n'

Vérification rapide avec tous (128) octets ascii:

Notez que tous les octets de 128 à 255 doivent être échappés.

for i in {0..127} ;do
    printf -v var \\%o $i
    printf -v var $var
    printf -v res "%q" "$var"
    esc=E
    [ "$var" = "$res" ] && esc=-
    printf "%02X %s %-7s\n" $i $esc "$res"
done |
    column

Cela doit rendre quelque chose comme:

00 E ''         1A E $'\032'    34 - 4          4E - N          68 - h      
01 E $'\001'    1B E $'\E'      35 - 5          4F - O          69 - i      
02 E $'\002'    1C E $'\034'    36 - 6          50 - P          6A - j      
03 E $'\003'    1D E $'\035'    37 - 7          51 - Q          6B - k      
04 E $'\004'    1E E $'\036'    38 - 8          52 - R          6C - l      
05 E $'\005'    1F E $'\037'    39 - 9          53 - S          6D - m      
06 E $'\006'    20 E \          3A - :          54 - T          6E - n      
07 E $'\a'      21 E \!         3B E \;         55 - U          6F - o      
08 E $'\b'      22 E \"         3C E \<         56 - V          70 - p      
09 E $'\t'      23 E \#         3D - =          57 - W          71 - q      
0A E $'\n'      24 E \$         3E E \>         58 - X          72 - r      
0B E $'\v'      25 - %          3F E \?         59 - Y          73 - s      
0C E $'\f'      26 E \&         40 - @          5A - Z          74 - t      
0D E $'\r'      27 E \'         41 - A          5B E \[         75 - u      
0E E $'\016'    28 E \(         42 - B          5C E \\         76 - v      
0F E $'\017'    29 E \)         43 - C          5D E \]         77 - w      
10 E $'\020'    2A E \*         44 - D          5E E \^         78 - x      
11 E $'\021'    2B - +          45 - E          5F - _          79 - y      
12 E $'\022'    2C E \,         46 - F          60 E \`         7A - z      
13 E $'\023'    2D - -          47 - G          61 - a          7B E \{     
14 E $'\024'    2E - .          48 - H          62 - b          7C E \|     
15 E $'\025'    2F - /          49 - I          63 - c          7D E \}     
16 E $'\026'    30 - 0          4A - J          64 - d          7E E \~     
17 E $'\027'    31 - 1          4B - K          65 - e          7F E $'\177'
18 E $'\030'    32 - 2          4C - L          66 - f      
19 E $'\031'    33 - 3          4D - M          67 - g      

Où le premier champ est la valeur hexadécimale d'octet, le second contient E si un caractère doit être échappé et le troisième champ affiche la présentation échappée du caractère.

Pourquoi ,?

Vous pourriez voir que certains caractères non toujours doivent être masqués, comme ,, } et {.

Donc pas toujours mais parfois:

echo test 1, 2, 3 and 4,5.
test 1, 2, 3 and 4,5.

ou

echo test { 1, 2, 3 }
test { 1, 2, 3 }

mais attention:

echo test{1,2,3}
test1 test2 test3

echo test\ {1,2,3}
test 1 test 2 test 3

echo test\ {\ 1,\ 2,\ 3\ }
test  1 test  2 test  3

echo test\ {\ 1\,\ 2,\ 3\ }
test  1, 2 test  3 
43
F. Hauri

Pour éviter que quelqu'un d'autre ait à RTFM ... dans bash:

Le fait de placer des caractères entre guillemets doubles préserve la valeur littérale de tous les caractères compris entre guillemets, à l'exception de $, `, \ et, lorsque l'extension de l'historique est activée, !.

... donc si vous échappez à ceux-ci (et à la citation elle-même, bien sûr), vous allez probablement bien.

Si vous adoptez une approche plus conservatrice consistant à "échapper au doute en cas de doute", vous devriez pouvoir éviter d'utiliser des caractères ayant une signification spéciale en évitant d'échapper aux caractères d'identification (par exemple, ASCII lettres, chiffres ou '_' ) Il est très peu probable que ceux-ci aient jamais une signification particulière (c'est-à-dire dans certains POSIX-ish Shell étranges) et doivent donc être évités.

30
Matthew

En utilisant le print '%q'technique , nous pouvons exécuter une boucle pour déterminer quels caractères sont spéciaux:

#!/bin/bash
special=$'`!@#$%^&*()-_+={}|[]\\;\':",.<>?/ '
for ((i=0; i < ${#special}; i++)); do
    char="${special:i:1}"
    printf -v q_char '%q' "$char"
    if [[ "$char" != "$q_char" ]]; then
        printf 'Yes - character %s needs to be escaped\n' "$char"
    else
        printf 'No - character %s does not need to be escaped\n' "$char"
    fi
done | sort

Il donne cette sortie:

No, character % does not need to be escaped
No, character + does not need to be escaped
No, character - does not need to be escaped
No, character . does not need to be escaped
No, character / does not need to be escaped
No, character : does not need to be escaped
No, character = does not need to be escaped
No, character @ does not need to be escaped
No, character _ does not need to be escaped
Yes, character   needs to be escaped
Yes, character ! needs to be escaped
Yes, character " needs to be escaped
Yes, character # needs to be escaped
Yes, character $ needs to be escaped
Yes, character & needs to be escaped
Yes, character ' needs to be escaped
Yes, character ( needs to be escaped
Yes, character ) needs to be escaped
Yes, character * needs to be escaped
Yes, character , needs to be escaped
Yes, character ; needs to be escaped
Yes, character < needs to be escaped
Yes, character > needs to be escaped
Yes, character ? needs to be escaped
Yes, character [ needs to be escaped
Yes, character \ needs to be escaped
Yes, character ] needs to be escaped
Yes, character ^ needs to be escaped
Yes, character ` needs to be escaped
Yes, character { needs to be escaped
Yes, character | needs to be escaped
Yes, character } needs to be escaped

Certains des résultats, comme , semblent un peu suspects. Il serait intéressant d'obtenir les contributions de @ CharlesDuffy à ce sujet.

21
codeforester

Les caractères à échapper dans Bourne ou POSIX Shell diffèrent de ceux de Bash. Généralement (très) Bash est un sur-ensemble de ces obus, de sorte que tout ce que vous échappez dans Shell devrait être évité dans Bash.

Une règle générale de Nice serait "en cas de doute, y échapper". Mais échapper à certains caractères leur confère une signification particulière, comme \n. Celles-ci sont répertoriées dans les pages man bash sous Quoting et echo.

Sinon, échappez à tout caractère non alphanumérique, c'est plus sûr. Je ne connais pas une seule liste définitive.

Les pages de manuel les répertorient toutes quelque part, mais pas au même endroit. Apprendre la langue, c’est le moyen d’en être sûr.

Celui qui m'a attrapé est !. C'est un caractère spécial (expansion de l'historique) dans Bash (et csh) mais pas dans Korn Shell. Même echo "Hello world!" donne des problèmes. L'utilisation de guillemets simples, comme d'habitude, supprime la signification particulière.

18
cdarke

Je suppose que vous parlez de bash strings. Il existe différents types de chaînes qui ont un ensemble différent d'exigences pour s'échapper. par exemple. Les chaînes de guillemets simples sont différentes des chaînes à guillemets doubles.

La meilleure référence est la section Citations du manuel bash.

Il explique quels personnages doivent échapper. Notez que certains caractères peuvent nécessiter un échappement en fonction des options activées, telles que le développement de l'historique.

4
Austin Phillips

J'ai remarqué que bash échappe automatiquement à certains caractères lors de l'utilisation de la saisie automatique.

Par exemple, si vous avez un répertoire nommé dir:A, bash se complétera automatiquement pour dir\:A

En utilisant cela, j'ai effectué quelques expériences en utilisant les caractères de la table ASCII et en ai dérivé les listes suivantes:

Caractères qui s'échappent par auto-complétion: (espace compris)

 !"$&'()*,:;<=>?@[\]^`{|}

Caractères que bash n'échappe pas:

#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

(J'ai exclu /, car il ne peut pas être utilisé dans les noms de répertoire)

3
yuri