Innanzitutto, separa zsh dal resto. Non è una questione di shell vecchie vs moderne: zsh si comporta in modo diverso. I progettisti di zsh hanno deciso di renderlo incompatibile con le shell tradizionali (Bourne, ksh, bash), ma più facile da usare.
In secondo luogo, è molto più facile usare le doppie virgolette continuamente che ricordare quando sono necessarie. Sono necessari per la maggior parte del tempo, quindi dovrai imparare quando non sono necessari, non quando sono necessari.
In breve, sono necessarie doppie virgolette ovunque sia previsto un elenco di parole o uno schema . Sono facoltativi in contesti in cui il parser prevede una stringa non elaborata.
Cosa succede senza virgolette
Si noti che senza virgolette doppie, accadono due cose.
- Innanzitutto, il risultato dell'espansione (il valore della variabile per una sostituzione di parametro simile
${foo}
o l'output del comando per una sostituzione di comando simile $(foo)
) viene suddiviso in parole ovunque contenga spazi bianchi.
Più precisamente, il risultato dell'espansione è diviso per ogni carattere che appare nel valore della IFS
variabile (carattere separatore). Se una sequenza di caratteri separatori contiene spazi bianchi (spazio, tabulazione o nuova riga), lo spazio bianco viene conteggiato come un singolo carattere; i separatori iniziali, finali o ripetuti non bianchi generano campi vuoti. Ad esempio, con IFS=" :"
, :one::two : three: :four
produce campi vuoti prima one
, tra one
e two
e (uno solo) tra three
e four
.
- Ogni campo risultante dalla divisione viene interpretato come un glob (un modello jolly) se contiene uno dei caratteri
\[*?
. Se quel modello corrisponde a uno o più nomi di file, il modello viene sostituito dall'elenco dei nomi di file corrispondenti.
Un'espansione variabile non quotata $foo
è colloquialmente nota come "operatore split + glob", al contrario della "$foo"
quale prende semplicemente il valore della variabile foo
. Lo stesso vale per la sostituzione dei comandi: "$(foo)"
è una sostituzione dei comandi, $(foo)
è una sostituzione dei comandi seguita da split + glob.
Dove puoi omettere le doppie virgolette
Ecco tutti i casi che mi vengono in mente in una shell in stile Bourne in cui è possibile scrivere una variabile o sostituire i comandi senza virgolette doppie e il valore viene interpretato letteralmente.
Sul lato destro di un compito.
var=$stuff
a_single_star=*
Nota che dopo hai bisogno delle doppie virgolette export
, perché è un normale built-in, non una parola chiave. Questo è vero solo in alcune shell come dash, zsh (in emulazione sh), yash o posh; bash e ksh trattano entrambi in modo export
speciale.
export VAR="$stuff"
In una case
dichiarazione.
case $var in …
Nota che hai bisogno di virgolette doppie in un modello di caso. La suddivisione delle parole non avviene in un caso, ma una variabile non quotata viene interpretata come un motivo, mentre una variabile tra virgolette viene interpretata come una stringa letterale.
a_star='a*'
case $var in
"$a_star") echo "'$var' is the two characters a, *";;
$a_star) echo "'$var' begins with a";;
esac
Tra doppie parentesi. Le parentesi doppie sono una sintassi speciale della shell.
[[ -e $filename ]]
Tranne che hai bisogno di virgolette doppie dove è previsto un modello o un'espressione regolare: sul lato destro di =
o ==
o !=
o =~
.
a_star='a*'
if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
fi
Hai bisogno di virgolette doppie come al solito tra parentesi singole [ … ]
perché sono normali sintassi della shell (è un comando che sembra essere chiamato [
). Vedi parentesi singole o doppie
In un reindirizzamento in shell POSIX non interattive (no bash
, né ksh88
).
echo "hello world" >$filename
Alcune shell, quando interattive, trattano il valore della variabile come un modello jolly. POSIX proibisce quel comportamento in shell non interattive, ma alcune shell tra cui bash (tranne che in modalità POSIX) e ksh88 (incluso quando trovato come POSIX (presumibilmente) sh
di alcuni Unici commerciali come Solaris) lo fanno ancora lì ( bash
tenta anche di dividere e il reindirizzamento ha esito negativo a meno che tale divisione + globbing non comporti esattamente una parola), motivo per cui è meglio citare gli obiettivi dei reindirizzamenti in uno sh
script nel caso in cui si desideri convertirlo in uno bash
script un giorno o eseguirlo su un sistema in cui si sh
trova non conformi su questo punto, o può essere di provenienza da shell interattive.
All'interno di un'espressione aritmetica. In effetti, è necessario escludere le virgolette affinché una variabile venga analizzata come espressione aritmetica.
expr=2*2
echo "$(($expr))"
Tuttavia, sono necessarie le virgolette intorno all'espansione aritmetica in quanto sono soggette alla suddivisione delle parole nella maggior parte delle shell come richiede POSIX (!?).
In un indice associativo dell'array.
typeset -A a
i='foo bar*qux'
a[foo\ bar\*qux]=hello
echo "${a[$i]}"
Una variabile non quotata e la sostituzione dei comandi possono essere utili in alcune rare circostanze:
- Quando il valore della variabile o l'output del comando è costituito da un elenco di modelli glob e si desidera espandere tali modelli nell'elenco dei file corrispondenti.
- Quando sai che il valore non contiene alcun carattere jolly, questo
$IFS
non è stato modificato e vuoi dividerlo in spazi bianchi.
- Quando vuoi dividere un valore per un certo personaggio: disabilita il globbing con
set -f
, imposta IFS
il carattere separatore (o lascialo solo per dividere in spazi bianchi), quindi fai l'espansione.
zsh
In zsh, puoi omettere le doppie virgolette il più delle volte, con alcune eccezioni.
$var
non si espande mai in più parole, tuttavia si espande nell'elenco vuoto (al contrario di un elenco contenente una sola parola vuota) se il valore di var
è la stringa vuota. Contrasto:
var=
print -l $var foo # prints just foo
print -l "$var" foo # prints an empty line, then foo
Allo stesso modo, si "${array[@]}"
espande a tutti gli elementi dell'array, mentre $array
si espande solo agli elementi non vuoti.
La @
bandiera espansione di parametro a volte richiede dei doppi apici l'intera sostituzione: "${(@)foo}"
.
La sostituzione dei comandi viene suddivisa in campi se non quotata: echo $(echo 'a'; echo '*')
stampa a *
(con un solo spazio) mentre echo "$(echo 'a'; echo '*')"
stampa la stringa a due righe non modificata. Utilizzare "$(somecommand)"
per ottenere l'output del comando in una sola parola, senza newline finali. Utilizzare "${$(somecommand; echo _)%?}"
per ottenere l'output esatto del comando, compresi i newline finali. Utilizzare "${(@f)$(somecommand)}"
per ottenere una matrice di linee dall'output del comando.
SH_WORD_SPLIT
dall'opzione.