In breve, cita tutto ciò in cui non è necessario che la shell esegua la divisione dei token e l'espansione dei caratteri jolly.
Le virgolette singole proteggono il testo tra di loro alla lettera. È lo strumento adatto quando è necessario assicurarsi che la shell non tocchi affatto la stringa. In genere, è il meccanismo di quoting di scelta quando non si richiede l'interpolazione variabile.
$ echo 'Nothing \t in here $will change'
Nothing \t in here $will change
$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.
Le virgolette sono adatte quando è richiesta l'interpolazione variabile. Con adattamenti adatti, è anche una buona soluzione quando hai bisogno di virgolette singole nella stringa. (Non v'è alcun modo semplice per sfuggire a una sola citazione tra virgolette singole, perché non esiste un meccanismo di fuga all'interno virgolette singole - se ci fosse, non avrebbero citare testualmente completamente.)
$ echo "There is no place like '$HOME'"
There is no place like '/home/me'
Nessun citazioni sono adatti quando si richiede specificamente alla shell di eseguire la divisione dei token e/o l'espansione di caratteri jolly.
Scissione di token;
$ words="foo bar baz"
$ for word in $words; do
> echo "$word"
> done
foo
bar
baz
Al contrario:
$ for word in "$words"; do echo "$word"; done
foo bar baz
(Il ciclo viene eseguito solo una volta, sopra il singolo, stringa tra apici.)
$ for word in '$words'; do echo "$word"; done
$words
(Il ciclo viene eseguito solo una volta, nel corso del singolo letterale - stringa quotata.)
Espansione jolly:
$ pattern='file*.txt'
$ ls $pattern
file1.txt file_other.txt
Al contrario:
$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory
(Non v'è alcun file chiamato letteralmente file*.txt
.)
$ ls '$pattern'
ls: cannot access $pattern: No such file or directory
(Non v'è alcun file chiamato $pattern
, sia!)
In termini più concreti, tutto ciò che contiene il nome del file di solito dovrebbe essere citato (perché i nomi dei file possono contenere spazi e altri metacaratteri della shell). Qualunque cosa contenga un URL dovrebbe di solito essere quotata (perché molti URL contengono metacaratteri della shell come ?
e &
). Qualunque cosa contenga una regex dovrebbe di solito essere citata (idem come idem). Tutto ciò che contiene spazi bianchi significativi diversi da spazi singoli tra personaggi non bianchi deve essere citato (perché altrimenti, la shell munge gli spazi bianchi in spazi effettivamente, singoli, e taglia ogni spazio bianco iniziale o finale).
Quando si sa che una variabile può contenere solo un valore che non contiene metacaratteri della shell, la quotatura è facoltativa. Pertanto, un valore non quotato $?
è fondamentalmente valido, poiché questa variabile può contenere solo un numero singolo. Tuttavia, "$?"
è anche corretto e consigliato per coerenza generale e correttezza (sebbene questa sia la mia raccomandazione personale, non una politica ampiamente riconosciuta).
I valori che non sono variabili seguono fondamentalmente le stesse regole, anche se è possibile sfuggire ai metacaratteri anziché quotarli. Per un esempio comune, un URL con un &
in esso sarà analizzato dalla shell come un comando di fondo a meno che il metacarattere sia sfuggito o citato:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
(Naturalmente, questo accade anche se l'URL è in una variabile non quotata). Per una stringa statica, le virgolette singole hanno più senso, anche se qualsiasi forma di citazione o di escaping funziona qui.
wget 'http://example.com/q&uack' # Single quotes preferred for a static string
wget "http://example.com/q&uack" # Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack # Backslash escape
wget http://example.com/q'&'uack # Only the metacharacter really needs quoting
L'ultimo esempio suggerisce anche un altro concetto utile, che mi piace chiamare "quotazione altalena". Se è necessario combinare virgolette singole e doppie, è possibile utilizzarle adiacenti l'una all'altra. Ad esempio, le seguenti stringhe citato
'$HOME '
"isn't"
' where `<3'
"' is."
può essere incollato insieme schiena contro schiena, formando un unico lunga stringa dopo tokenizzazione e citare la rimozione.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Questo non è terribilmente leggibile, ma è una tecnica comune e quindi utile da conoscere.
A parte, script should usually not use ls
for anything. Per espandere un carattere jolly, basta ... usarlo.
$ printf '%s\n' $pattern # not ``ls -1 $pattern''
file1.txt
file_other.txt
$ for file in $pattern; do # definitely, definitely not ``for file in $(ls $pattern)''
> printf 'Found file: %s\n' "$file"
> done
Found file: file1.txt
Found file: file_other.txt
(Il ciclo è completamente superfluo nel secondo esempio;. printf
funziona specificamente bene con argomenti multipli stat
troppo Ma ciclo su carattere jolly è un problema comune, e spesso fatto in modo errato..)
Una variabile contenente un elenco di token su cui eseguire il loop o un carattere jolly da espandere è vista meno frequentemente, quindi a volte abbreviamo "cita tutto a meno che tu non sappia esattamente cosa stai facendo".
Non ci sono domande stupide. Bene, ci sono _, ma questo non è uno di questi :-) – paxdiablo
Vedere anche http://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable- shell in-bash-posix – tripleee
Questa domanda ottiene molti duplicati, molti dei quali non riguardano variabili, quindi ho cambiato il nome in "valore" anziché in "variabile". Spero che questo aiuti più persone a trovare questo argomento. – tripleee