Ci sono due cose che succedono qui: in primo luogo, bash riconosce la doppia virgoletta ASCII normale, "
(codice carattere 0x22) come una doppia citazione; non riconosce l'unicode di fantasia left double-quote, “
(Unicode U + 201C, codifica UTF-8 0xe2809c) e la corrispondente doppia virgola destra, ”
(unicode U + 201D, codifica UTF-8 0xe2809d) come qualcosa di diverso da sequenze casuali di byte (o forse come caratteri casuali, se si utilizza un locale UTF-8). Questa è la cosa fondamentale da realizzare: per quanto riguarda bash, “
e ”
non sono effettivamente virgolette , sono solo cose che assomigliano a virgolette quando sono stampato.
La seconda complicazione è che le virgolette unicode sono caratteri multibyte, quindi se bash non è in un locale UTF-8 potrebbe trattare alcuni dei byte in modo diverso rispetto ad altri (!)
Per vedere l'effetto della prima cosa, prova a sostituire ogni occorrenza di una virgola doppia con la stringa WIBBLE
- un'altra sequenza arbitraria che non ha alcun significato speciale per la shell:
$ echo "The path to my home directory is: $HOME bar"
The path to my home directory is: /Users/gordon bar
$ echo “The path to my home directory is: $HOME bar”
“The path to my home directory is: /Users/gordon bar”
$ echo WIBBLEThe path to my home directory is: $HOME barWIBBLE
WIBBLEThe path to my home directory is: /Users/gordon barWIBBLE
Nel primo comando (con virgolette ASCII), le virgolette vengono analizzate e rimosse da bash prima che gli argomenti vengano passati al comando echo
e quindi non stampati. Nella seconda e terza (con doppie virgolette fantasiose e WIBBLE al posto di virgolette semplici), vengono semplicemente considerate come parte delle stringhe da passare a echo
, quindi echo
le stampa come parte del suo output.
$ echo "The path to my home directory is: $HOME (foo) bar"
The path to my home directory is: /Users/gordon (foo) bar
$ echo “The path to my home directory is: $HOME (foo) bar”
-bash: syntax error near unexpected token '('
$ echo WIBBLEThe path to my home directory is: $HOME (foo) barWIBBLE
-bash: syntax error near unexpected token '('
Nel secondo e nel terzo comando (con virgolette fantasiose e WIBBLE), bash vede parentesi in una porzione non quotata del comando (ricorda: per quanto riguarda bash, le virgolette sono in realtà non cita ), in un luogo in cui non sono consentiti dalla sintassi della shell e, pertanto, si lamentano.
$ echo “The path to my home directory is: $HOME”
“The path to my home directory is: ??
$ echo WIBBLEThe path to my home directory is: $HOMEWIBBLE
WIBBLEThe path to my home directory is:
Qui sta succedendo qualcosa di strano. Nel secondo comando, cerca una variabile denominata HOMEWIBBLE
, non trovandola, quindi sostituendola con spazio vuoto. Nel caso del primo, con le doppie virgolette fantasiose, mi sembra che tratti ogni byte della codifica UTF-8 di ”
come carattere separato, trattando il primo come parte del nome della variabile (di nuovo causando la mancata rilevazione della variabile), quindi passando semplicemente il secondo e il terzo byte, dando un carattere UTF-8 non valido, che viene stampato come ??
. Usando un dump esadecimale per avere una migliore idea di cosa sta succedendo dà questo:
$ echo “$HOME”
“??
$ echo “$HOME” | xxd -g1
00000000: e2 80 9c 80 9d 0a ......
Si noti che il primo “
passa per il fine e si presenta nel dump esadecimale come e2 80 9c
(la doppia citazione fittizia con UTF-8 prevista), ma dopo questo è solo 80 9d
- il primo e2
della seconda citazione fantasia è stata mangiata in qualche modo! (A proposito, il 0a
alla fine è un avanzamento di riga, che segna la fine dell'output.) Per vedere cosa sta accadendo, fammi definire una variabile di shell come HOME
+ il primo byte della codifica di ”
, e guarda cosa succede:
$ eval $'HOME\xe2=foo'
$ echo “$HOME”
“foo??
$ echo “$HOME” | xxd -g1
00000000: e2 80 9c 66 6f 6f 80 9d 0a ...foo...
... Ecco cosa sta succedendo: sta trattando il primo byte della codifica della doppia citazione come parte del nome della variabile, sostituendolo (se definito), e quindi passando semplicemente attraverso il secondo e il terzo byte orfani, lasciando UTF-8 non valido. Non sono sicuro che si tratti di un bug di base, di una stranezza del suo parsing o di cosa.
Comunque, i dettagli sono piuttosto disordinati, ma il take-away dovrebbe essere chiaro: non usare virgolette fantasiose negli script della shell; non funzioneranno correttamente. Lo stesso vale per le virgolette fantasia e altri segni di punteggiatura Unicode.