Quelle est la différence entre les guillemets «…», «…», $ '…' et $ «…»?

49

Parfois , je vois des scripts utilisent toutes ces différentes manières de citer un texte: "...", '...', $'...'et $"...". Pourquoi utilise-t-on tant de types de devis différents?

Est-ce qu'ils se comportent différemment ou ont une incidence sur ce que je peux faire à l'intérieur d'eux?

Michael Homer
la source
1
Duplication possible entre sites. Cette réponse fournit un résumé de (ou des liens vers) la sémantique de tous les différents types de citations.
Chepner

Réponses:

66

Tous 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 citations interprètent différentes séquences d'échappement à l'intérieur de celles-ci ( \something), ou n'autorisent ou n'autorisent pas les interpolations variables ( $something) et d'autres types d'expansion à l'intérieur de celles-ci.

En bref:

  • '...' est entièrement littéral.
  • "..." autorise les variables et les guillemets incorporés.
  • $'...'effectue des échappements de caractères comme \n, mais ne développe pas les variables.
  • $"..." est pour les traductions en langues humaines en bash et ksh.

'Guillemets simples'

Tout ce que vous écrivez entre guillemets simples est traité littéralement et non traité du tout. Les barres obliques inverses et les signes dollar n'ont pas de signification particulière. Cela signifie que vous ne pouvez pas échapper à un caractère (y compris d'autres guillemets simples!), Interpoler une variable ou utiliser une autre fonction du 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

Le dernier est compliqué - il y a deux chaînes entre guillemets simples et du texte non entre guillemets. Le premier contient I\. Le texte non dn\'tcité contient un guillemet simple échappé au niveau du shell . Il ne commence donc pas une chaîne entre guillemets et est inclus sous forme de caractère littéral (so, dn't). La dernière chaîne citée est juste ve. Tous ces éléments sont regroupés dans un seul mot de la manière habituelle dont le shell fonctionne.

Un idiome assez courant pour combiner du texte littéral et des variables consiste à les exécuter ensemble de la manière suivante:

'let x="'$PATH\"

aura pour résultat

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

en tant que mot unique (il est préférable de doubler les guillemets $PATHau cas où - des espaces ou des caractères globaux dans la valeur de la variable pourraient être traités autrement - mais pour des raisons de lisibilité, je ne l'ai pas).


"Double citation"

Dans les guillemets doubles, deux types d’expansion sont traités et vous pouvez utiliser une barre oblique inverse pour échapper des caractères afin d’empêcher le traitement des extensions ou des échappées.

Il y a deux catégories d'expansion qui se produisent entre guillemets:

À l’intérieur des guillemets, une barre oblique inverse peut empêcher ces extensions en le plaçant avant le $ou `. Il peut également échapper à une double citation de clôture, il \"est donc uniquement inclus "dans votre chaîne ou dans une autre barre oblique inverse. Toute autre barre oblique inversée est préservée littéralement - il n'y a pas d'échappatoire pour produire d'autres caractères et elle n'est pas supprimée.

Certains de ces exemples agissent différemment d'avant, d'autres non:

"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 guillemets permet de traiter les caractères d'échappement des barres obliques inverses de style C, mais pas les variables incorporées ni les substitutions. Il est le seul genre de citer que le soutien caractère échappe .

C'est une extension de ksh, maintenant supportée par Bash, zsh et quelques autres shells. Il ne fait pas encore partie de la norme POSIX et ne peut donc pas être utilisé par les scripts extrêmement portables, mais un script Bash ou ksh est gratuit.

Tous ces évasions peuvent être utilisés avec leurs significations C: \a, \b, \f, \n, \r, \t, \v, et les évasions littérales \\, \', \"et \?. Ils supportent également les extensions \e(caractère d'échappement) et dans Bash et ksh \cx(ce qui serait entré par Ctrl-x , par exemple, \cMest le retour chariot). Les coquillages ont une gamme d'extensions mineures qui leur sont propres.

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

  • \nnn, un seul octet avec une valeur octale nnn
  • \xHH, un seul octet avec une valeur hexadécimale HH
  • \uHHHH, le code Unicode dont l'index hexadécimal est HHHH
  • \UHHHHHHHH, le 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 préservés littéralement, de sorte que vous ne pouvez pas y inclure une 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'                  => 🕴☺

La plupart de ces évasions , vous pouvez simuler à l' aide de la printfcommande , si POSIX ne nécessite que \\, \a, \b, \f, \n, \r, \t, \vet \nnntravailler là - bas. Vous pouvez utiliser la substitution de commande pour incorporer un à l' printfintérieur des guillemets doubles si nécessaire: "Path:$(printf '\t')$PATH".


$ "Traduction locale"

Il s'agit d'une extension spécifique à ksh et à Bash pour la localisation de chaînes textuelles en langage naturel. Elle recherche la partie située entre les guillemets d'un catalogue de messages. Il effectue d’abord toutes les extensions de guillemets doubles. Si la chaîne ne se trouve pas 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 simples.


Un point à noter est qu’aucun type de citation ne permet à la fois le développement de paramètres incorporés et les échappements de caractères incorporés. Dans la plupart des cas où vous le souhaiteriez, vous seriez mieux (plus sûr) d'utiliser printf:

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

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

Une autre est que tous ces styles de citation créent un seul "mot" dans le shell, sauf si $@ une extension de tableau ${x[@]}est utilisée entre guillemets doubles. Les deux formes de guillemets simples sont toujours un mot et ne sont jamais développées davantage.

Michael Homer
la source
$"..."est aussi de ksh93, ajouté à bash en 2.0.
Stéphane Chazelas
Il n'y a pas \cXdedans zsh. C'est \CXou \C-Xlà (a \cdéjà une signification spéciale dans echo)
Stéphane Chazelas
'let x="'$PATH\"est erroné dans des contextes de liste dans des shells autres que zshas $PATHnot cite (donc serait sujet à split + glob que vous ne voudriez pas ici).
Stéphane Chazelas
Vous voudrez peut-être préciser que vous parlez d'obus de type Korn, le traitement des devis est différent dans csh, rc, poisson ...
Stéphane Chazelas
@ StéphaneChazelas Définir le "contexte de liste".
Isaac