Come programmatore principalmente Java, trovo bash if
–then
costruire abbastanza confuso, specialmente per quanto riguarda gli spazi bianchi. Qualcuno può spiegare perché il primo funziona, ma non il secondo o il terzo?
#works
if [ -n $1 ]; then echo "parameterized"; fi
#output: ./links: Zeile 1: [-n: Kommando nicht gefunden.
if [-n $1 ]; then echo "parameterized"; fi
#output: ./links: Zeile 1: [: Fehlende `]'
if [ -n $1]; then echo "parameterized"; fi
Risposta accettata:
L'incoerenza è in gran parte dovuta a ragioni storiche.
L'uso delle parentesi come comando condizionale è arrivato dopo l'uso delle parentesi nei modelli di caratteri jolly. Quindi al momento [ -n foo ]
è entrato in scena, [foo]
già significava “un file il cui nome è f
o o
”. Mentre pochi usi dell'operatore parentesi nella pratica sarebbero stati in conflitto con usi realistici delle parentesi nei caratteri jolly, gli autori hanno scelto di non rischiare di rompere gli script esistenti cambiando la sintassi. Questa scelta progettuale ha anche semplificato l'implementazione:inizialmente [
è stato implementato come comando esterno, cosa che non sarebbe stata possibile se fosse stato inserito lo spazio dopo [
era stato facoltativo. (I sistemi moderni hanno ancora [
come comando esterno, ma quasi tutte le shell moderne lo hanno anche integrato.)
Per ragioni simili, il tuo codice "funzionante" è effettivamente errato nella maggior parte dei casi. $1
non significa “il valore del parametro 1”:significa “prendere il valore del parametro 1, dividerlo in parole separate in uno spazio bianco (o qualunque sia il valore di IFS
è) e interpreta ogni parola come un modello glob”. Il modo per scrivere "il valore del parametro 1" richiede virgolette:"$1"
. Vedere Quando è necessaria la doppia virgoletta? per il nocciolo della questione. Non è necessario capirlo; tutto ciò che devi ricordare è:metti sempre virgolette tra le sostituzioni delle variabili "$foo"
e sostituzioni di comandi "$(foo)"
. Quindi:
if [ -n "$1" ]; then …
In bash, ksh e zsh, ma non in sh normale, puoi anche usare parentesi doppie. Parentesi singole [ … ]
vengono analizzati come un normale comando (e infatti [
è un comando ordinario, sebbene di solito integrato). Le doppie parentesi sono un costrutto sintattico separato e puoi omettere le doppie virgolette la maggior parte delle volte.
if [[ -n $1 ]]; then …
Tuttavia, c'è un'eccezione:[[ "$foo" = "$bar" ]]
per verificare se le due variabili hanno lo stesso valore sono necessarie virgolette intorno a $bar
, altrimenti $bar
viene interpretato come un modello di caratteri jolly. Ancora una volta, invece di ricordare i dettagli, potresti anche usare sempre le virgolette doppie.