Unterschied zwischen einfachen und doppelten Anführungszeichen in Bash

Antworten:

579

Einfache Anführungszeichen interpolieren nichts, doppelte Anführungszeichen jedoch. Zum Beispiel: Variablen, Backticks, bestimmte Escapezeichen \usw.

Beispiel:

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

Das Bash-Handbuch enthält Folgendes:

3.1.2.2 Einfache Anführungszeichen

Durch das Einschließen von Zeichen in einfache Anführungszeichen ( ') wird der Literalwert jedes Zeichens in den Anführungszeichen beibehalten. Ein einfaches Anführungszeichen darf nicht zwischen einfachen Anführungszeichen stehen, selbst wenn ein Backslash vorangestellt ist.

3.1.2.3 Doppelte Anführungszeichen

Zeichen in doppelten Anführungszeichen (umschließende ") bewahrt den wörtlichen Wert aller Zeichen innerhalb der Anführungszeichen, mit Ausnahme von $, `, \, und, wenn die Geschichte Erweiterung aktiviert ist, !. Die Zeichen $und `behalten ihre besondere Bedeutung in doppelten Anführungszeichen (siehe Shell-Erweiterungen ). Der Backslash behält seine besondere Bedeutung nur , wenn sie durch eine der folgenden Zeichen folgen: $, `, ",\oder Newline. In doppelten Anführungszeichen werden Backslashes entfernt, auf die eines dieser Zeichen folgt. Backslashes vor Zeichen ohne besondere Bedeutung bleiben unverändert. Ein doppeltes Anführungszeichen kann in doppelten Anführungszeichen angegeben werden, indem ein Backslash vorangestellt wird. Wenn diese Option aktiviert ist, wird die Verlaufserweiterung ausgeführt, es sei denn, ein !in doppelten Anführungszeichen angegebenes Zeichen wird mit einem Backslash maskiert. Der Backslash vor dem !wird nicht entfernt.

Die speziellen Parameter *und @haben in doppelten Anführungszeichen eine besondere Bedeutung (siehe Shell-Parametererweiterung ).

Adam Batkin
quelle
41
Für alle, die nicht wissen, was "interpolieren" bedeutet: en.wikipedia.org/wiki/String_interpolation
Kolob Canyon
Was ist, wenn Sie ein git_promptGit verwenden PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', das von Git bereitgestellt wird ? Sie schlagen vor, es wie folgt zu verwenden. Die Git-Eingabeaufforderung sollte demnach nicht funktionieren. Haben die PS#Variablen etwas Besonderes ? oder warum funktioniert es, wenn es nicht die Interpolation macht.
Ekiim
@ekiim Dieser genaue Text wird (unverändert) in gesetzt PS1. Versuche echo $PS1zu sehen, was ich meine. Wird PS1jedoch vor der Anzeige ausgewertet (siehe PROMPTINGAbschnitt in der Bash-Manpage). Versuchen Sie es, um dies zu testen PS1='$X'. Sie werden keine Eingabeaufforderung haben. Dann laufen X=foound plötzlich ist Ihre Eingabeaufforderung "foo" ( PS1wurde ausgewertet, wenn eingestellt statt angezeigt , hätten Sie immer noch keine Eingabeaufforderung).
Adam Batkin
262

Die akzeptierte Antwort ist großartig. Ich mache eine Tabelle, die zum schnellen Verständnis des Themas beiträgt. Die Erklärung beinhaltet eine einfache Variable asowie ein indiziertes Array arr.

Wenn wir setzen

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

und dann echoden Ausdruck in der zweiten Spalte, würden wir das Ergebnis / Verhalten erhalten, das in der dritten Spalte gezeigt wird. In der vierten Spalte wird das Verhalten erläutert.

 # | 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
---+-------------+-------------+--------------------------------------------------------------------

Siehe auch:

Codeforester
quelle
1
Die akzeptierte Antwort lautet am Ende: The special parameters * and @ have special meaning when in double quotesWie kommt es also zu "*"Ergebnissen *?
Anddero
2
@ Karl-AnderoMere, weil sie in diesem Fall überhaupt nicht als Parameter erweitert werden. "$@"und "$*"sind Parametererweiterungen. "@"und "*"sind nicht.
Charles Duffy
@ CharlesDuffy Danke, es macht jetzt Sinn!
Anddero
3
Nummer 9 echo "\'", gibt mich zurück \'.
MaxGyver
@ MaxGyver: Danke, dass du darauf hingewiesen hast. Ich habe die Antwort aktualisiert.
Codeforester
233

Wenn Sie sich darauf beziehen, was passiert, wenn Sie etwas wiedergeben, geben die einfachen Anführungszeichen buchstäblich wieder, was Sie zwischen ihnen haben, während die doppelten Anführungszeichen Variablen zwischen ihnen auswerten und den Wert der Variablen ausgeben.

Zum Beispiel dies

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

wird dies geben:

double quotes gives you sometext
single quotes gives you $MYVAR
likso
quelle
11

Andere haben es sehr gut erklärt und wollen nur mit einfachen Beispielen geben.

Um Text können einfache Anführungszeichen verwendet werden, um zu verhindern, dass die Shell Sonderzeichen interpretiert. Dollarzeichen, Leerzeichen, kaufmännisches Und, Sternchen und andere Sonderzeichen werden ignoriert, wenn sie in einfache Anführungszeichen gesetzt werden.

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

Es wird dies geben:

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

Das einzige, was nicht in einfache Anführungszeichen gesetzt werden kann, ist ein einfaches Anführungszeichen.

Doppelte Anführungszeichen verhalten sich ähnlich wie einfache Anführungszeichen, außer dass doppelte Anführungszeichen es der Shell weiterhin ermöglichen, Dollarzeichen, hintere Anführungszeichen und umgekehrte Schrägstriche zu interpretieren. Es ist bereits bekannt, dass Backslashes die Interpretation eines einzelnen Sonderzeichens verhindern. Dies kann in doppelten Anführungszeichen hilfreich sein, wenn ein Dollarzeichen anstelle einer Variablen als Text verwendet werden muss. Außerdem können doppelte Anführungszeichen maskiert werden, damit sie nicht als Ende einer Zeichenfolge in Anführungszeichen interpretiert werden.

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

Es wird dies geben:

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

Es kann auch bemerkt werden, dass das Apostroph, das sonst als der Anfang einer Zeichenfolge in Anführungszeichen interpretiert würde, in doppelten Anführungszeichen ignoriert wird. Variablen werden jedoch interpretiert und durch ihre Werte in doppelten Anführungszeichen ersetzt.

$ echo "The current Oracle SID is $ORACLE_SID"

Es wird dies geben:

The current Oracle SID is test

Zurück Anführungszeichen sind völlig anders als einfache oder doppelte Anführungszeichen. Anstatt verwendet zu werden, um die Interpretation von Sonderzeichen zu verhindern, erzwingen hintere Anführungszeichen die Ausführung der von ihnen eingeschlossenen Befehle. Nachdem die beigefügten Befehle ausgeführt wurden, wird ihre Ausgabe anstelle der hinteren Anführungszeichen in der ursprünglichen Zeile ersetzt. Dies wird anhand eines Beispiels klarer.

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

Es wird dies geben:

Monday, September 28, 2015 
Sree
quelle
3

Es gibt einen klaren Unterschied zwischen der Verwendung von ' 'und " ".

Wenn ' 'etwas verwendet wird, wird keine "Transformation oder Übersetzung" durchgeführt. Es wird so gedruckt, wie es ist.

Mit " ", was auch immer es umgibt, wird es in seinen Wert "übersetzt oder transformiert".

Mit Übersetzung / Transformation meine ich Folgendes: Alles innerhalb der einfachen Anführungszeichen wird nicht in ihre Werte "übersetzt". Sie werden so genommen, wie sie in Anführungszeichen stehen. Beispiel: a=23, dann echo '$a'produzieren wird $aauf der Standardausgabe. Während echo "$a"produziert 23auf der Standardausgabe.

a_r
quelle
1
Was meinst du mit "Übersetzung" oder "Transformation"?
Nico Haase
Diese Antwort ist ziemlich verwirrend und fügt nichts zu den vorhandenen guten Antworten hinzu.
Codeforester
2
Dies war meiner Meinung nach eine kurze, prägnante Antwort, ohne übermäßig wortreich zu sein, was für mich leicht zu verstehen war. Wenn Sie Übersetzung / Transformation sagen, bedeutet dies, dass doppelte Anführungszeichen die Variable erweitern, während einfache Anführungszeichen die Variable nicht erweitern.
B_e_n_n_y_
1
Ja, das ist die beste Antwort. Dies sollte die akzeptierte Antwort sein.
Jamey Kirby
3

Da dies die De-facto-Antwort beim Umgang mit Anführungszeichen in ist bash, werde ich einen weiteren Punkt hinzufügen, der in den obigen Antworten beim Umgang mit den arithmetischen Operatoren in der Shell übersehen wurde.

Die bashShell unterstützt zwei Arten der arithmetischen Operation, eine, die durch den integrierten letBefehl und den $((..))Operator definiert wird. Ersteres wertet einen arithmetischen Ausdruck aus, während letzteres eher eine zusammengesetzte Aussage ist.

Es ist wichtig zu verstehen, dass der arithmetische Ausdruck, der mit verwendet letwird, wie alle anderen Shell-Befehle einer wortaufteilenden Pfadnamenerweiterung unterzogen wird. Es muss also richtig zitiert und entkommen werden.

Siehe dieses Beispiel bei der Verwendung let

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

Die Verwendung von einfachen Anführungszeichen ist hier absolut in Ordnung, da hier keine variablen Erweiterungen erforderlich sind. Betrachten Sie einen Fall von

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

würde kläglich scheitern, da sich die $barunter einfachen Anführungszeichen nicht erweitern würden und doppelt in Anführungszeichen gesetzt werden müssen

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

Dies sollte einer der Gründe sein, die $((..))immer überbeansprucht werden sollten let. Weil der Inhalt darin keiner Wortaufteilung unterliegt. Das vorherige Beispiel mit letkann einfach geschrieben werden als

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

Denken Sie immer daran, $((..))ohne einfache Anführungszeichen zu verwenden

Obwohl das $((..))mit doppelten Anführungszeichen verwendet werden kann, hat es keinen Zweck, da es keinen Inhalt enthalten kann, der das doppelte Anführungszeichen benötigt. Stellen Sie einfach sicher, dass es nicht in einfachen Anführungszeichen steht.

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

In einigen besonderen Fällen, in denen der $((..))Operator in einer Zeichenfolge in einfachen Anführungszeichen verwendet wird, müssen Sie Anführungszeichen so interpolieren, dass der Operator entweder nicht in Anführungszeichen gesetzt oder in doppelte Anführungszeichen gesetzt wird. Stellen Sie sich beispielsweise einen Fall vor, in dem Sie versuchen, den Operator in einer curlAnweisung zu verwenden, um bei jeder Anforderung einen Zähler zu übergeben

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

Beachten Sie die Verwendung verschachtelter doppelter Anführungszeichen, ohne die die Literalzeichenfolge $((reqcnt++))an das requestCounterFeld übergeben wird.

Inian
quelle
2
Charles Duffy macht einen guten Fall hier für Doppel zitiert $((...))auch. Es mag "ein wenig" paranoid sein und es ist IFS=0zum Beispiel ziemlich unwahrscheinlich , aber es ist sicherlich nicht unmöglich :)
PesaThe
Es gibt auch die Legacy- $[[...]]Syntax, aber vielleicht haben Sie sie zu Recht vergessen.
Tripleee