web-dev-qa-db-fra.com

Quelle est la différence entre les guillemets "...", '...', $ '...' et $ "..."?

Parfois, je vois des scripts utiliser toutes ces différentes façons de citer du texte: "...", '...', $'...', et $"...". Pourquoi y a-t-il tant de types de devis différents?

Se comportent-ils différemment ou affectent-ils ce que je peux faire en eux?

52
Michael Homer

Tout cela signifie 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 en leur sein (\something), Ou autorisent ou n'autorisent pas les interpolations variables ($something) Et d'autres types d'expansion à l'intérieur.

En bref:

  • '...' Est entièrement littéral.
  • "..." Autorise les variables et les guillemets intégrés.
  • $'...' Effectue des échappements de caractères comme \n, Mais ne développe pas les variables.
  • $"..." Est destiné aux traductions en langage humain dans Bash et ksh.

'Citations simples'

Tout ce que vous écrivez entre guillemets simples est traité littéralement et n'est pas traité du tout. Les contre-obliques et les signes dollar n'ont pas de signification particulière. Cela signifie que vous ne pouvez pas utiliser de barre oblique inverse pour échapper un caractère (y compris d'autres guillemets simples!), Interpoler une variable ou utiliser une autre fonction Shell.

Tous ces exemples donnent littéralement ce qui est écrit entre les guillemets:

'hello world'                     => hello world
'/pkg/bin:$PATH'                  => /pkg/bin:$PATH
'hello\nworld'                    => hello\nworld
'`echo abc`'                      => `echo abc`
'I\'dn\'t've'                     => I\dn'tve

La dernière est compliquée - il y a deux chaînes de guillemets simples exécutées avec du texte sans guillemets. Le premier contient I\. Le texte sans guillemets dn\'t Contient une seule citation échappée au niveau du shell, il ne démarre donc pas de chaîne entre guillemets et est inclus en tant que caractère littéral (donc, dn't). La dernière chaîne entre guillemets est simplement ve. Tous ces éléments sont regroupés dans un seul mot de la manière habituelle utilisée par Shell.

Un idiome quelque peu courant pour combiner du texte littéral et des variables est de les exécuter ensemble comme ça:

'let x="'$PATH\"

aura pour résultat

let x="/usr/bin:/bin"

comme un seul mot (il vaut mieux mettre entre guillemets $PATH également au cas où - les espaces ou les caractères globulaires dans la variable valeur peuvent être traités autrement - mais pour un exemple de course lisible, je ne l'ai pas).


"Double guillemets"

À 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 extensions ou les échappements d'être traitées.

Il existe deux catégories d'expansion qui se produisent entre guillemets doubles:

À l'intérieur des guillemets, une barre oblique inversée peut empêcher ces extensions en la plaçant avant le $ Ou `. Il peut également échapper à un guillemet double de fermeture, donc \" Inclut juste " Dans votre chaîne, ou une autre barre oblique inverse. Toute autre barre oblique inversée est conservé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 qu'auparavant, et d'autres pas:

"hello world"                     => hello world
"/pkg/bin:$PATH"                  => /pkg/bin:/bin:/usr/bin
"hello\nworld"                    => hello\nworld
"hello\\nworld"                   => hello\nworld
"`echo abc`"                      => abc
"I\'dn\'t've"                     => I\'dn\'t've
"I'dn't've"                       => I'dn't've
"I\"dn\"t've"                     => I"dn"t've

$ 'Citation ANSI-C'

Ce type de citation permet de traiter les échappements de barre oblique inverse de style C, mais pas les variables ou substitutions incorporées. C'est le type de citation seulement 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. Il ne fait pas encore partie de la norme POSIX et les scripts portables maximaux 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 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 entré par Ctrl-x , par exemple \cM est le retour chariot). Les coquilles ont une gamme d'extensions mineures qui leur sont propres.

Il permet également quatre types d'échappements de caractères génériques:

  • \nnn, Un seul octet avec une valeur octale nnn
  • \xHH, Un seul octet avec une valeur hexadécimale [~ # ~] hh [~ # ~]
  • \uHHHH, Le point de code Unicode dont l'index hexadécimal est [~ # ~] hhhh [~ # ~]
  • \UHHHHHHHH, 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.

$'hello world'                    => hello world
$'/pkg/bin:$PATH'                 => /pkg/bin:$PATH
$'hello\nworld'                   => hello
                                     world
$'`echo abc`'                     => `echo abc`
$'I\'dn\'t\'ve'                   => I'dn't've
$'\U1f574\u263A'                  => ????☺

Vous pouvez simuler la plupart de ces échappements en utilisant la commande printf , 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 commandes pour incorporer un printf à l'intérieur de guillemets doubles si nécessaire: "Path:$(printf '\t')$PATH".


$ "Traduction locale"

Il s'agit d'une extension spécifique à ksh et Bash pour localiser les chaînes textuelles en langage naturel et recherche la partie à l'intérieur des guillemets dans un catalogue de messages. Il effectue d'abord toutes les extensions de 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 réguliers.


Un point à noter est qu'il existe non 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 le voudriez, il serait préférable (plus sûr) d'utiliser printf:

printf 'New path: \e[1m%s\e[0m' "/pkg/bin:$PATH:"

Ceci sépare clairement quelles parties sont sujettes à l'échappement de caractère et quelles sont les valeurs de données.

Un autre est que tous ces styles de guillemets créent un seul "mot" dans le shell, sauf$@ Ou une extension de tableau ${x[@]} Est utilisée entre guillemets doubles . Les deux formulaires de guillemets simples sont toujours un seul mot et n'ont jamais été développés davantage.

68
Michael Homer