Qualcuno potrebbe dirmi se dovrei avvolgere le virgolette intorno alle variabili in uno script di shell?
Ad esempio, è il seguente corretto:
xdg-open $URL
[ $? -eq 2 ]
o
xdg-open "$URL"
[ "$?" -eq "2" ]
E se sì, perché?
Qualcuno potrebbe dirmi se dovrei avvolgere le virgolette intorno alle variabili in uno script di shell?
Ad esempio, è il seguente corretto:
xdg-open $URL
[ $? -eq 2 ]
o
xdg-open "$URL"
[ "$?" -eq "2" ]
E se sì, perché?
Risposte:
Regola generale: citala se può essere vuota o contenere spazi (o qualsiasi spazio bianco in realtà) o caratteri speciali (caratteri jolly). Non citare stringhe con spazi spesso porta alla shell che spezza un singolo argomento in molti.
$?
non ha bisogno di virgolette poiché è un valore numerico. Se ne ha $URL
bisogno dipende da cosa permetti lì dentro e se vuoi ancora un argomento se è vuoto.
Tendo a citare sempre le stringhe solo per abitudine poiché è più sicuro in quel modo.
IFS=0
, allora echo $?
può essere molto sorprendente.
cp $source1 $source2 $dest
, ma se per qualche motivo imprevisto dest
non viene impostato, il terzo argomento appena scompare, e sarà in silenzio copiare source1
sopra source2
invece di dare voi un errore appropriato per la destinazione vuota (come sarebbe se si fosse citato ogni argomento).
quote it if...
ha il processo di pensiero all'indietro - le virgolette non sono qualcosa che aggiungi quando è necessario, sono qualcosa che rimuovi quando è necessario. Avvolgere sempre stringhe e script tra apici a meno che non dovete usare le virgolette (ad esempio, per lasciare una variabile espandere) o necessità di utilizzare senza virgolette (ad esempio, per fare globbing e il nome del file di espansione).
In breve, citare 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 adeguato quando è necessario assicurarsi che la shell non tocchi affatto la stringa. In genere, è il meccanismo di quotazione preferito quando non è richiesta 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 doppie sono adatte quando è richiesta l'interpolazione variabile. Con adattamenti adeguati, è anche una buona soluzione quando hai bisogno di virgolette singole nella stringa. (Non esiste un modo semplice per sfuggire a una singola virgoletta tra virgolette singole, perché non esiste un meccanismo di escape all'interno di virgolette singole - se esistesse, non citerebbero completamente alla lettera.)
$ echo "There is no place like '$HOME'"
There is no place like '/home/me'
Nessuna virgoletta è adatta quando si richiede specificamente alla shell di eseguire la suddivisione dei token e / o l'espansione dei caratteri jolly.
Divisione del 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 la singola stringa tra virgolette.)
$ for word in '$words'; do echo "$word"; done
$words
(Il ciclo viene eseguito solo una volta, sopra la stringa letterale a virgoletta singola.)
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 esiste alcun file chiamato letteralmente file*.txt
.)
$ ls '$pattern'
ls: cannot access $pattern: No such file or directory
(Non c'è nemmeno un file chiamato $pattern
!)
In termini più concreti, tutto ciò che contiene un nome di file dovrebbe di solito essere citato (poiché i nomi di file possono contenere spazi bianchi e altri metacaratteri della shell). Qualunque cosa contenga un URL dovrebbe di solito essere quotata (perché molti URL contengono metacaratteri come ?
e &
). Tutto ciò che contiene un regex dovrebbe essere di solito citato (idem idem). Tutto ciò che contiene spazi bianchi significativi diversi dai singoli spazi tra caratteri non bianchi deve essere citato (perché altrimenti, la shell immergerà lo spazio bianco in, efficacemente, spazi singoli e taglierà qualsiasi spazio bianco iniziale o finale).
Quando sai che una variabile può contenere solo un valore che non contiene metacaratteri di shell, la quotazione è facoltativa. Pertanto, un non quotato $?
va sostanzialmente bene, perché questa variabile può sempre e solo contenere un solo numero. Tuttavia, "$?"
è anche corretto e raccomandato per coerenza e correttezza generali (sebbene questa sia la mia raccomandazione personale, non una politica ampiamente riconosciuta).
I valori che non sono variabili seguono sostanzialmente le stesse regole, anche se potresti quindi sfuggire ai metacaratteri invece di citarli. Per un esempio comune, un URL con un &
al suo interno verrà analizzato dalla shell come comando in background a meno che il metacarattere non sia salvato o citato:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
(Naturalmente, ciò accade anche se l'URL si trova in una variabile non quotata.) Per una stringa statica, le virgolette singole hanno più senso, anche se qui funziona qualsiasi forma di quotazione o escape.
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 devi mescolare virgolette singole e doppie, puoi usarle una accanto all'altra. Ad esempio, le seguenti stringhe tra virgolette
'$HOME '
"isn't"
' where `<3'
"' is."
può essere incollato insieme schiena contro schiena, formando una singola stringa lunga dopo la tokenizzazione e la rimozione delle quotazioni.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Questo non è terribilmente leggibile, ma è una tecnica comune e quindi buono a sapersi.
A parte questo, gli script di solito non dovrebbero essere usati ls
per nulla. 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 in quest'ultimo esempio; in printf
particolare funziona bene con più argomenti.stat
Anche. Il ciclo su una corrispondenza jolly è un problema comune e spesso eseguito in modo errato.)
Una variabile contenente un elenco di token su cui eseguire il loop o un carattere jolly da espandere viene vista meno frequentemente, quindi a volte abbreviamo per "citare tutto a meno che tu non sappia esattamente cosa stai facendo".
Ecco una formula in tre punti per le virgolette in generale:
Virgolette
In contesti in cui vogliamo sopprimere la divisione delle parole e il globbing. Anche in contesti in cui vogliamo che il letterale sia trattato come una stringa, non una regex.
Virgolette singole
In letterali a stringhe dove vogliamo sopprimere l'interpolazione e il trattamento speciale delle barre rovesciate. In altre parole, le situazioni in cui l'uso di virgolette doppie sarebbe inappropriata.
Senza virgolette
In contesti in cui siamo assolutamente sicuri che non ci siano problemi di divisione o di frantumazione delle parole o che desideriamo dividere e frantumare le parole .
Esempi
Virgolette
"StackOverflow rocks!"
, "Steve's Apple"
)"$var"
, "${arr[@]}"
)"$(ls)"
, "`ls`"
)"/my dir/"*
)"single'quote'delimited'string"
)"${filename##*/}"
)Virgolette singole
'Really costs $$!'
, 'just a backslash followed by a t: \t'
)'The "crux"'
)$'\n\t'
)$'{"table": "users", "where": "first_name"=\'Steve\'}'
)Senza virgolette
$$
, $?
, $#
etc.)((count++))
, "${arr[idx]}"
,"${string:start:length}"
[[ ]]
espressione interna che è libera da problemi di frazionamento e frantumazione di parole (questa è una questione di stile e le opinioni possono variare ampiamente)for word in $words
)for txtfile in *.txt; do ...
)~
essere interpretati come $HOME
( ~/"some dir"
ma non "~/some dir"
)Guarda anche:
"ls" "/"
La frase "tutti i contesti di stringa" deve essere qualificata con più attenzione.
[[ ]]
, la citazione è importante sul lato destro di =
/ ==
e =~
: fa la differenza tra l'interpretazione di una stringa come modello / regex o letteralmente.
$'...'
) dovrebbero avere la loro sezione.
"ls" "/"
posto del più comune ls /
, e lo prendo come un grosso difetto nelle linee guida.
case
:)
In genere uso citato come "$var"
per sicurezza, a meno che non sia sicuro che $var
non contenga spazio.
Uso $var
un modo semplice per unire le linee:
lines="`cat multi-lines-text-file.txt`"
echo "$lines" ## multiple lines
echo $lines ## all spaces (including newlines) are zapped
Per utilizzare le variabili nello script della shell, utilizzare "" le variabili tra virgolette come quella tra virgolette significa che la variabile può contenere spazi o caratteri speciali che non influiranno sull'esecuzione dello script della shell. Altrimenti se sei sicuro di non avere spazi o caratteri speciali nel nome della tua variabile, puoi usarli senza "".
Esempio:
echo "$ url name" - (Può essere usato in ogni momento)
echo "$ url name" - (Non può essere usato in tali situazioni quindi prendi precauzioni prima di usarlo)