Différence entre les guillemets simples et doubles dans Bash

Réponses:

580

Les guillemets simples n'interpoleront rien, mais les guillemets doubles le seront. Par exemple: variables, backticks, certaines \échappées, etc.

Exemple:

$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")

Le manuel de Bash dit ceci:

3.1.2.2 Citations uniques

La présence de caractères entre guillemets simples ( ') préserve la valeur littérale de chaque caractère entre guillemets. Un guillemet simple ne peut pas apparaître entre guillemets simples, même lorsqu'il est précédé d'une barre oblique inverse.

3.1.2.3 Double guillemets

Caractères Enfermer guillemets doubles ( ") préserve la valeur littérale de tous les caractères dans les citations, à l'exception de $, `, \et, lorsque l' expansion de l' histoire est activée, !. Les caractères $et `conservent leur signification particulière entre guillemets doubles (voir les extensions de shell ). La barre oblique inverse conserve sa signification que lorsqu'il est suivi d'un des caractères suivants: $, `, ",\ou nouvelle ligne. Dans les guillemets doubles, les barres obliques inverses suivies de l'un de ces caractères sont supprimées. Les barres obliques inverses précédant les caractères sans signification particulière ne sont pas modifiées. Un guillemet double peut être cité entre guillemets doubles en le précédant d'une barre oblique inverse. Si cette option est activée, l'expansion de l'historique sera effectuée, sauf si une !apparition entre guillemets doubles est échappée à l'aide d'une barre oblique inverse. La barre oblique inverse précédant le !n'est pas supprimée.

Les paramètres spéciaux *et @ont une signification particulière lorsqu'ils sont entre guillemets (voir Expansion des paramètres du shell ).

Adam Batkin
la source
41
Pour ceux qui ne savent pas ce que signifie "interpoler": en.wikipedia.org/wiki/String_interpolation
Kolob Canyon
1
Qu'en est-il lorsque vous utilisez un git_promptgit fourni, ils suggèrent de l'utiliser comme ceci PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', git prompt , selon cela ne devrait pas fonctionner. Y a-t-il quelque chose de spécial dans les PS#variables? ou pourquoi ça marche si ça ne fait pas l'interpolation.
ekiim
1
@ekiim Ce texte exact est défini (inchangé) dans PS1. Essayez echo $PS1de voir ce que je veux dire. Mais PS1est évalué avant d'être affiché (voir la PROMPTINGsection dans la page de manuel bash). Pour tester cela, essayez PS1='$X'. Vous n'aurez aucune invite. Ensuite, exécutez X=fooet tout à coup votre invite est "foo" (avait PS1été évaluée lorsqu'elle était définie au lieu d'être affichée, vous n'auriez toujours pas d'invite).
Adam Batkin
263

La réponse acceptée est excellente. Je fais un tableau qui aide à une compréhension rapide du sujet. L'explication implique une variable simple aainsi qu'un tableau indexé arr.

Si nous définissons

a=apple      # a simple variable
arr=(apple)  # an indexed array with a single element

puis echol'expression dans la deuxième colonne, nous obtiendrions le résultat / comportement affiché dans la troisième colonne. La quatrième colonne explique le comportement.

 # | Expression  | Result      | Comments
---+-------------+-------------+--------------------------------------------------------------------
 1 | "$a"        | apple       | variables are expanded inside ""
 2 | '$a'        | $a          | variables are not expanded inside ''
 3 | "'$a'"      | 'apple'     | '' has no special meaning inside ""
 4 | '"$a"'      | "$a"        | "" is treated literally inside ''
 5 | '\''        | **invalid** | can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
 6 | "red$arocks"| red         | $arocks does not expand $a; use ${a}rocks to preserve $a
 7 | "redapple$" | redapple$   | $ followed by no variable name evaluates to $
 8 | '\"'        | \"          | \ has no special meaning inside ''
 9 | "\'"        | \'          | \' is interpreted inside "" but has no significance for '
10 | "\""        | "           | \" is interpreted inside ""
11 | "*"         | *           | glob does not work inside "" or ''
12 | "\t\n"      | \t\n        | \t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13 | "`echo hi`" | hi          | `` and $() are evaluated inside ""
14 | '`echo hi`' | `echo hi`   | `` and $() are not evaluated inside ''
15 | '${arr[0]}' | ${arr[0]}   | array access not possible inside ''
16 | "${arr[0]}" | apple       | array access works inside ""
17 | $'$a\''     | $a'         | single quotes can be escaped inside ANSI-C quoting
18 | "$'\t'"     | $'\t'       | ANSI-C quoting is not interpreted inside ""
19 | '!cmd'      | !cmd        | history expansion character '!' is ignored inside ''
20 | "!cmd"      | cmd args    | expands to the most recent command matching "cmd"
21 | $'!cmd'     | !cmd        | history expansion character '!' is ignored inside ANSI-C quotes
---+-------------+-------------+--------------------------------------------------------------------

Voir également:

codeforester
la source
1
La réponse acceptée dit à la fin, The special parameters * and @ have special meaning when in double quotesalors comment se fait-il que les "*"résultats soient *?
anddero
2
@ Karl-AnderoMere, car ils ne sont pas du tout développés comme paramètres dans ce cas. "$@"et "$*"sont des extensions de paramètres. "@"et "*"ne le sont pas.
Charles Duffy
@CharlesDuffy Merci, c'est logique maintenant!
anddero
3
Numéro 9, echo "\'"me renvoie \'.
MaxGyver
@MaxGyver: merci de l'avoir pointé. J'ai mis à jour la réponse.
codeforester
233

Si vous faites référence à ce qui se passe lorsque vous faites écho à quelque chose, les guillemets simples feront littéralement écho à ce que vous avez entre eux, tandis que les guillemets doubles évalueront les variables entre eux et afficheront la valeur de la variable.

Par exemple, cette

#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'

donnera ceci:

double quotes gives you sometext
single quotes gives you $MYVAR
likso
la source
11

D'autres ont très bien expliqué et veulent juste donner des exemples simples.

Des guillemets simples peuvent être utilisés autour du texte pour empêcher le shell d'interpréter des caractères spéciaux. Les signes dollar, les espaces, les esperluettes, les astérisques et autres caractères spéciaux sont tous ignorés lorsqu'ils sont placés entre guillemets simples.

$ echo 'All sorts of things are ignored in single quotes, like $ & * ; |.' 

Cela donnera ceci:

All sorts of things are ignored in single quotes, like $ & * ; |.

La seule chose qui ne peut pas être mise entre guillemets simples est un guillemet simple.

Les guillemets doubles agissent de la même manière que les guillemets simples, sauf que les guillemets doubles permettent toujours au shell d'interpréter les signes dollar, les guillemets et les barres obliques inverses. Il est déjà connu que les barres obliques inverses empêchent l'interprétation d'un seul caractère spécial. Cela peut être utile entre guillemets doubles si un signe dollar doit être utilisé comme texte au lieu d'une variable. Il permet également d'échapper les guillemets doubles afin qu'ils ne soient pas interprétés comme la fin d'une chaîne entre guillemets.

$ echo "Here's how we can use single ' and double \" quotes within double quotes"

Cela donnera ceci:

Here's how we can use single ' and double " quotes within double quotes

On peut également remarquer que l'apostrophe, qui autrement serait interprétée comme le début d'une chaîne entre guillemets, est ignorée entre guillemets. Cependant, les variables sont interprétées et remplacées par leurs valeurs entre guillemets doubles.

$ echo "The current Oracle SID is $ORACLE_SID"

Cela donnera ceci:

The current Oracle SID is test

Les guillemets sont totalement différents des guillemets simples ou doubles. Au lieu d'être utilisés pour empêcher l'interprétation des caractères spéciaux, les guillemets arrière forcent en fait l'exécution des commandes qu'ils contiennent. Une fois les commandes jointes exécutées, leur sortie est remplacée à la place des guillemets dans la ligne d'origine. Ce sera plus clair avec un exemple.

$ today=`date '+%A, %B %d, %Y'`
$ echo $today 

Cela donnera ceci:

Monday, September 28, 2015 
Sree
la source
3

Il existe une distinction claire entre l'utilisation de ' 'et " ".

Lorsqu'il ' 'est utilisé autour de quoi que ce soit, aucune "transformation ou traduction" n'est effectuée. Il est imprimé tel quel.

Avec " ", tout ce qui l'entoure, est "traduit ou transformé" en sa valeur.

Par traduction / transformation, je veux dire ce qui suit: Tout ce qui se trouve dans les guillemets simples ne sera pas "traduit" à leurs valeurs. Ils seront pris tels quels dans les guillemets. Exemple: a=23, puis echo '$a'produira $asur la sortie standard. Alors que echo "$a"produira 23sur la sortie standard.

a_r
la source
1
Qu'entendez-vous par «traduction» ou «transformation»?
Nico Haase
Cette réponse est assez déroutante et n'ajoute rien en plus des bonnes réponses existantes.
codeforester
2
C'était une réponse concise courte à mon avis sans être trop verbeuse et facile à comprendre pour moi. Lorsque vous dites traduction / transformation, cela signifie que les guillemets doubles développeront la variable là où les guillemets simples ne développeront pas la variable.
B_e_n_n_y_
1
Oui, c'est la meilleure réponse. Ce devrait être la réponse acceptée.
Jamey Kirby
3

Étant donné que c'est la réponse de facto lorsque vous traitez avec des guillemets bash, j'ajouterai un autre point manquant dans les réponses ci-dessus, lorsque vous traitez avec les opérateurs arithmétiques dans le shell.

Le bashshell prend en charge deux méthodes de calcul arithmétique, l'une définie par la letcommande intégrée et l' $((..))opérateur. Le premier évalue une expression arithmétique tandis que le second est davantage une déclaration composée.

Il est important de comprendre que l'expression arithmétique utilisée avec letsubit une expansion de séparation de mots et de chemin comme toutes les autres commandes shell. Il faut donc bien citer et échapper.

Voir cet exemple lors de l'utilisation let

let 'foo = 2 + 1'
echo $foo
3

Utiliser des guillemets simples ici est tout à fait correct ici, car il n'y a pas besoin d'extensions de variables ici, considérons un cas de

bar=1
let 'foo = $bar + 1'

échouerait lamentablement, car les $barguillemets simples ne seraient pas développeraient et doivent être

let 'foo = '"$bar"' + 1'

Cela devrait être l'une des raisons, il $((..))faut toujours considérer l'utilisation excessive let. Parce qu'à l'intérieur, le contenu n'est pas sujet à la séparation des mots. L'exemple précédent utilisant letpeut être simplement écrit comme

(( bar=1, foo = bar + 1 ))

N'oubliez pas d'utiliser $((..)) sans guillemets simples

Bien que le $((..))puisse être utilisé avec des guillemets doubles, il n'a aucun intérêt car il ne peut pas contenir un contenu qui aurait besoin du guillemet double. Assurez-vous simplement qu'il ne s'agit pas d'un guillemet simple.

printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2

Dans certains cas particuliers d'utilisation de l' $((..))opérateur à l'intérieur d'une seule chaîne entre guillemets, vous devez interpoler les guillemets de manière à ce que l'opérateur soit laissé entre guillemets ou entre guillemets doubles. Par exemple, considérons un cas, lorsque vous tentez d'utiliser l'opérateur à l'intérieur d'uncurl instruction pour passer un compteur chaque fois qu'une demande est faite, faites

curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'

Notez l'utilisation de guillemets doubles imbriqués à l'intérieur, sans lesquels la chaîne littérale $((reqcnt++))est passée à requestCounterfield.

Inian
la source
2
Charles Duffy plaide également ici pour la double citation $((...)). C'est peut-être "un peu" paranoïaque et très peu probable IFS=0par exemple, mais ce n'est certainement pas impossible :)
PesaThe
Il y a aussi la $[[...]]syntaxe héritée, mais vous avez peut-être eu raison de l'oublier.
tripleee