Parfois, je vois des scripts shell utiliser toutes ces différentes façons de citer du texte :"..."
, '...'
, $'...'
, et $"..."
. Pourquoi utilise-t-on autant de types de devis différents ?
Se comportent-ils différemment ou affectent-ils ce que je peux faire à l'intérieur ?
Réponse acceptée :
Tous ces éléments signifient quelque chose de différent, et vous pouvez écrire différentes choses à l'intérieur (ou les mêmes choses, avec une signification différente). Différents types de guillemets interprètent différentes séquences d'échappement à l'intérieur (something
), ou autorisez ou non les interpolations de variables ($something
) et d'autres types d'expansion à l'intérieur.
En bref :
'...'
est entièrement littéral."..."
autorise à la fois les variables et les guillemets intégrés.$'...'
effectue des échappements de caractères commen
, mais ne développe pas les variables.$"..."
est pour les traductions en langage humain dans Bash et ksh.
'Apostrophes'
Tout ce que vous écrivez entre guillemets simples est traité littéralement et pas du tout traité. Les barres obliques inverses et les signes dollar n'y ont aucune signification particulière. Cela signifie que vous ne pouvez pas échapper un caractère par une barre oblique inverse (y compris d'autres guillemets simples !), interpoler une variable ou utiliser toute autre fonctionnalité du shell.
Tous ces exemples donnent littéralement ce qui est écrit entre les guillemets :
Code | Résultat |
---|---|
'hello world' | bonjour le monde |
'/pkg/bin:$PATH' | /pkg/bin :$PATH |
'hellonworld' | hellonworld |
'`echo abc`' | `echo abc` |
'I'dn't've' | Je ne sais pas |
Le dernier est compliqué - il y en a deux les chaînes entre guillemets simples sont exécutées avec du texte sans guillemets. Le premier contient I
. Le texte sans guillemets dn't
contient un guillemet simple qui est échappé au niveau du shell , donc il ne commence pas une chaîne entre guillemets et est inclus en tant que caractère littéral (donc, dn't
). La chaîne finale entre guillemets est juste ve
. Tous ces éléments sont regroupés en un seul mot de la manière habituelle dont fonctionne le shell.
Un idiome assez courant pour combiner du texte littéral et des variables consiste à les exécuter ensemble comme ceci :
'let x="'$PATH"
entraînera
let x="/usr/bin:/bin"
comme un seul mot (mieux vaut mettre entre guillemets $PATH
ainsi qu'au cas où - des espaces ou des caractères globaux dans la variable valeur peut être traité autrement - mais pour un exemple courant lisible, je ne l'ai pas fait).
« Guillemets doubles »
À l'intérieur des guillemets doubles, deux types d'expansion sont traités, et vous pouvez utiliser une barre oblique inverse pour échapper les caractères afin d'empêcher les expansions ou les échappements d'être traités.
Il existe deux catégories d'expansion qui se produisent à l'intérieur des guillemets :
- Ceux commençant par
$
(extension de paramètre$abc
et${abc}
, substitution de commande$(...)
, et développement arithmétique$((...))
); - Substitution de commandes avec guillemets inverses
`abc`
;
À l'intérieur des guillemets, une barre oblique inverse peut inhiber ces expansions en la plaçant avant le $
ou `
. Il peut également échapper à un guillemet double fermant, donc "
inclut uniquement "
dans votre chaîne, ou une autre barre oblique inverse. Toute autre barre oblique inverse est préservée littéralement - il n'y a pas d'échappement pour produire d'autres caractères, et elle n'est pas supprimée.
Certains de ces exemples agissent différemment d'avant, et d'autres non :
Code | Résultat |
---|---|
"hello world" | bonjour le monde |
"/pkg/bin:$PATH" | /pkg/bin:/bin:/usr/bin |
"hellonworld" | hellonworld |
"hello\nworld" | hellonworld |
"`echo abc`" | abc |
"I'dn't've" | Je n'aurais pas |
"I'dn't've" | Je n'aurais pas |
"I"dn"t've" | Je n'ai pas |
$'ANSI-C entre guillemets'
Ce type de guillemets permet de traiter les échappements antislash de style C, mais pas variables imbriquées ou substitutions. C'est le seul type de citation qui prend en charge les caractères d'échappement .
Il s'agit d'une extension de ksh, désormais prise en charge dans Bash, zsh et certains autres shells également. Il ne fait pas encore partie de la norme POSIX et les scripts les plus portables ne peuvent donc pas l'utiliser, mais un script Bash ou ksh est libre de le faire.
Tous ces échappements peuvent être utilisés avec leurs significations en C :a
, b
, f
, n
, r
, t
, v
, et les échappements littéraux \
, '
, "
, et ?
. Ils prennent également en charge les extensions e
(caractère d'échappement) et dans Bash et ksh cx
(ce qui serait saisi par Ctrl-x, par exemple cM
est un retour chariot). Les shells ont leur propre gamme d'extensions mineures.
Il permet également quatre types d'échappements de caractères génériques :
nnn
, un seul octet avec une valeur octale nnnxHH
, un seul octet avec une valeur hexadécimale HHuHHHH
, le point de code Unicode dont l'index hexadécimal est HHHHUHHHHHHHH
, le point de code Unicode dont l'index hexadécimal est HHHHHHHH
Tous ces chiffres sont facultatifs après le premier.
$
et `
n'ont aucune signification et sont conservés littéralement, vous ne pouvez donc pas y inclure de variable.
Code | Résultat |
---|---|
$'hello world' | bonjour le monde |
$'/pkg/bin:$PATH' | /pkg/bin :$PATH |
$'hellonworld' | bonjour monde |
$'`echo abc`' | `echo abc` |
$'I'dn't've' | Je n'aurais pas |
$'U1f574u263A' | 🕴☺ |
Vous pouvez simuler la plupart de ces évasions en utilisant le printf
commande, bien que POSIX ne nécessite que \
, a
, b
, f
, n
, r
, t
, v
, et nnn
pour y travailler. Vous pouvez utiliser la substitution de commande pour intégrer un printf
entre guillemets doubles si nécessaire :"Path:$(printf 't')$PATH"
.
$"Traduction locale"
Il s'agit d'une extension spécifique à ksh et Bash pour localiser des chaînes textuelles en langage naturel et rechercher la partie à l'intérieur des guillemets dans un catalogue de messages. Il exécute d'abord tous les développements entre guillemets doubles. Si la chaîne n'est pas trouvée dans la base de données de traduction, elle est utilisée comme sa propre traduction. L'hypothèse intégrée est que les chaînes sont en anglais.
Vous ne voulez probablement pas utiliser celui-ci, mais si vous le voyez, vous pouvez généralement le traiter comme des guillemets doubles réguliers.
Un point à noter est qu'il n'y a pas type de citation qui permet à la fois l'expansion des paramètres intégrés et les échappements de caractères intégrés. Dans la plupart des cas où vous voudriez cela, vous feriez mieux (plus en sécurité) d'utiliser printf
:
printf 'New path: e[1m%se[0m' "/pkg/bin:$PATH:"
Cela sépare clairement les parties soumises à l'échappement de caractères et celles qui sont des valeurs de données.
Une autre est que tous ces styles de guillemets créent un seul "mot" dans le shell, à moins que [email protected]
ou une extension de tableau ${x[@]}
est utilisé entre guillemets doubles. Les deux formes de guillemet simple sont toujours un mot et ne sont jamais développées davantage.