Differenza tra virgolette singole e doppie in Bash


Risposte:


580

Le virgolette singole non interpolano nulla, ma le virgolette doppie lo fanno. Ad esempio: variabili, backtick, determinate \escape, ecc.

Esempio:

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

Il manuale di Bash ha questo da dire:

3.1.2.2 Virgolette singole

Racchiudere i caratteri tra virgolette singole ( ') conserva il valore letterale di ciascun carattere tra virgolette. Una virgoletta singola potrebbe non verificarsi tra virgolette singole, anche se preceduta da una barra rovesciata.

3.1.2.3 Virgolette doppie

Racchiudere caratteri tra virgolette ( ") conserva il valore letterale di tutti i caratteri all'interno delle virgolette, ad eccezione di $, `, \e, quando l'espansione della cronologia è abilitata, !. I personaggi $e `mantengono il loro significato speciale tra virgolette (vedi Espansioni della shell ). Il backslash mantiene il suo significato speciale solo quando seguito da uno dei seguenti caratteri: $, `, ",\o newline. Tra virgolette doppie, le barre rovesciate seguite da uno di questi caratteri vengono rimosse. Le barre rovesciate che precedono i caratteri senza un significato speciale vengono lasciate non modificate. Una virgoletta doppia può essere citata tra virgolette precedenti precedendola con una barra rovesciata. Se abilitato, l'espansione della cronologia verrà eseguita a meno che non !venga evitato di apparire tra virgolette usando una barra rovesciata. La barra rovesciata che precede il !non viene rimossa.

I parametri speciali *e @hanno un significato speciale quando tra virgolette (vedi Shell parametro di espansione ).


41
Per chiunque non sappia cosa significhi "interpolare": en.wikipedia.org/wiki/String_interpolation
Kolob Canyon

1
Che dire di quando stai usando un git_promptche git fornisce loro suggeriscono di usarlo in questo modo PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', git prompt , in base a ciò non dovrebbe funzionare. C'è qualcosa di speciale nelle PS#variabili? o perché funziona se non sta eseguendo l'interpolazione.
ekiim

1
@ekiim Quel testo esatto è impostato (invariato) in PS1. Prova echo $PS1a capire cosa intendo. Ma PS1viene valutato prima di essere visualizzato (vedere la PROMPTINGsezione nella manpage di bash). Per provarlo, prova PS1='$X'. Non avrai nessun prompt. Quindi esegui X=fooe improvvisamente il tuo prompt è "pippo" ( PS1valutato se impostato invece di visualizzato non avresti ancora alcun prompt).
Adam Batkin,

263

La risposta accettata è ottima. Sto preparando un tavolo che aiuta a comprendere rapidamente l'argomento. La spiegazione riguarda una variabile semplice ae una matrice indicizzata arr.

Se impostiamo

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

e quindi echol'espressione nella seconda colonna, otterremmo il risultato / comportamento mostrato nella terza colonna. La quarta colonna spiega il comportamento.

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

Guarda anche:


1
La risposta accettata dice alla fine, The special parameters * and @ have special meaning when in double quotesquindi come mai i "*"risultati *?
anddero,

2
@ Karl-AnderoMere, perché in quel caso non sono affatto espansi come parametri. "$@"e "$*"sono espansioni di parametri. "@"e "*"non lo sono.
Charles Duffy,

@CharlesDuffy Grazie, ora ha senso!
anddero,

3
Numero 9, echo "\'"mi restituisce \'.
MaxGyver,

@MaxGyver: grazie per averlo indicato. Ho aggiornato la risposta.
codeforester,

233

Se ti riferisci a ciò che accade quando fai eco a qualcosa, le virgolette singole fanno letteralmente eco a ciò che hai tra loro, mentre le virgolette doppie valutano le variabili tra loro e generano il valore della variabile.

Ad esempio, questo

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

darà questo:

double quotes gives you sometext
single quotes gives you $MYVAR

11

Altri hanno spiegato molto bene e vogliono solo dare esempi semplici.

Virgolette singole possono essere usate attorno al testo per impedire alla shell di interpretare caratteri speciali. Segni di dollaro, spazi, e commerciali, asterischi e altri caratteri speciali sono tutti ignorati se racchiusi tra virgolette singole.

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

Darà questo:

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

L'unica cosa che non può essere inserita tra virgolette singole è una virgoletta singola.

Le virgolette doppie funzionano in modo simile alle virgolette singole, ad eccezione delle virgolette doppie che consentono comunque alla shell di interpretare i simboli del dollaro, le virgolette posteriori e le barre rovesciate. È già noto che le barre rovesciate impediscono l'interpretazione di un singolo carattere speciale. Questo può essere utile tra virgolette se un simbolo di dollaro deve essere usato come testo anziché per una variabile. Consente inoltre di evitare le virgolette doppie in modo che non vengano interpretate come la fine di una stringa tra virgolette.

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

Darà questo:

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

Si può anche notare che l'apostrofo, che sarebbe altrimenti interpretato come l'inizio di una stringa tra virgolette, viene ignorato tra virgolette doppie. Le variabili, tuttavia, vengono interpretate e sostituite con i loro valori tra virgolette doppie.

$ echo "The current Oracle SID is $ORACLE_SID"

Darà questo:

The current Oracle SID is test

Le virgolette posteriori sono completamente diverse dalle virgolette singole o doppie. Invece di essere utilizzati per impedire l'interpretazione di caratteri speciali, le virgolette in realtà forzano l'esecuzione dei comandi che racchiudono. Dopo aver eseguito i comandi allegati, il loro output viene sostituito al posto delle virgolette posteriori nella riga originale. Ciò sarà più chiaro con un esempio.

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

Darà questo:

Monday, September 28, 2015 

3

Esiste una chiara distinzione tra l'uso di ' 'e " ".

Quando ' 'viene utilizzato attorno a qualsiasi cosa, non viene eseguita alcuna "trasformazione o traduzione". Viene stampato così com'è.

Con " ", qualunque cosa circonda, viene "tradotto o trasformato" nel suo valore.

Per traduzione / trasformazione intendo quanto segue: Qualsiasi cosa tra virgolette singole non verrà "tradotta" nei loro valori. Saranno presi come sono tra virgolette. Esempio:, a=23quindi echo '$a'produrrà $asu output standard. Considerando echo "$a"che produrrà 23sulla produzione standard.


1
Cosa intendi con "traduzione" o "trasformazione"?
Nico Haase,

Questa risposta è piuttosto confusa e non aggiunge nulla in aggiunta alle buone risposte esistenti.
codeforester

2
Questa è stata una breve risposta concisa secondo me senza essere eccessivamente prolissa, che era facile da comprendere per me. Quando si dice traduzione / trasformazione, significano che le virgolette doppie espandono la variabile in cui le virgolette singole non espandono la variabile.
B_e_n_n_y_

1
Sì, questa è la risposta migliore. Questa dovrebbe essere la risposta accettata.
Jamey Kirby,

3

Poiché questa è la risposta di fatto quando si tratta di virgolette bash, aggiungerò un altro punto mancante nelle risposte sopra, quando si tratta degli operatori aritmetici nella shell.

La bashshell supporta due modi per eseguire operazioni aritmetiche, una definita dal letcomando integrato e $((..))dall'operatore. Il primo valuta un'espressione aritmetica mentre il secondo è più un'istruzione composta.

È importante capire che l'espressione aritmetica usata con letsubisce l'espansione del frazionamento delle parole, proprio come qualsiasi altro comando shell. Pertanto, è necessario eseguire una corretta quotazione e fuga.

Vedi questo esempio durante l'utilizzo let

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

L'uso di virgolette singole qui è assolutamente perfetto qui, poiché non è necessario per espansioni variabili qui, prendere in considerazione un caso di

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

fallirebbe miseramente, poiché le $barvirgolette singole sottostanti non si espandono e devono essere racchiuse tra virgolette

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

Questo dovrebbe essere uno dei motivi, $((..))dovrebbe essere sempre considerato oltre l'utilizzo let. Perché al suo interno, i contenuti non sono soggetti a suddivisione in parole. L'esempio precedente usando letpuò essere semplicemente scritto come

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

Ricorda sempre di usare $((..))senza virgolette singole

Sebbene $((..))possa essere utilizzato con virgolette doppie, non vi è alcun motivo in quanto non può contenere un contenuto che avrebbe bisogno della virgoletta doppia. Assicurati solo che non sia quotato singolarmente.

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

In alcuni casi speciali di utilizzo $((..))dell'operatore all'interno di una singola stringa tra virgolette, potrebbe essere necessario interpolare le virgolette in modo tale che l'operatore rimanga senza virgolette o tra virgolette doppie. Ad esempio, prendere in considerazione un caso, quando si sta tentando di utilizzare l'operatore all'interno di curlun'istruzione per passare un contatore ogni volta che viene effettuata una richiesta, fare

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

Notare l'uso di virgolette doppie nidificate all'interno, senza le quali la stringa letterale $((reqcnt++))viene passata al requestCountercampo.


2
Charles Duffy fa un buon caso qui per la doppia citazione $((...))pure. Potrebbe essere "un po '" paranoico e abbastanza improbabile, ad IFS=0esempio, ma certamente non è impossibile :)
PesaIl

C'è anche la $[[...]]sintassi legacy, ma forse avevi ragione a dimenticarla.
triplo il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.