Risposte:
RISPOSTA BREVE
Come altri hanno già detto, dovresti sempre citare le variabili per prevenire comportamenti strani. Quindi usa echo "$ foo" invece di echo $ foo .
RISPOSTA LUNGA
Penso che questo esempio meriti ulteriori spiegazioni perché c'è molto di più di quanto potrebbe sembrare in faccia.
Posso vedere dove arriva la tua confusione perché dopo aver eseguito il tuo primo esempio probabilmente hai pensato a te stesso che la shell ovviamente sta facendo:
Quindi dal tuo primo esempio:
me$ FOO="BAR * BAR"
me$ echo $FOO
Dopo che l'espansione dei parametri è equivalente a:
me$ echo BAR * BAR
E dopo l'espansione del nome del file è equivalente a:
me$ echo BAR file1 file2 file3 file4 BAR
E se digiti semplicemente echo BAR * BAR
nella riga di comando vedrai che sono equivalenti.
Quindi probabilmente hai pensato a te stesso "se sfuggo al *, posso impedire l'espansione del nome file"
Quindi dal tuo secondo esempio:
me$ FOO="BAR \* BAR"
me$ echo $FOO
Dopo l'espansione dei parametri dovrebbe essere equivalente a:
me$ echo BAR \* BAR
E dopo l'espansione del nome file dovrebbe essere equivalente a:
me$ echo BAR \* BAR
E se provi a digitare "echo BAR \ * BAR" direttamente nella riga di comando, verrà effettivamente stampato "BAR * BAR" perché l'espansione impedisce l'espansione del nome file.
Quindi perché usare $ foo non ha funzionato?
È perché c'è una terza espansione che ha luogo: la rimozione delle quotazioni. Dalla rimozione manuale del preventivo bash è:
Dopo le espansioni precedenti, tutte le occorrenze non quotate dei caratteri '\', '' 'e' "'che non sono risultate da una delle espansioni di cui sopra vengono rimosse.
Quindi ciò che accade è quando si digita il comando direttamente nella riga di comando, il carattere di escape non è il risultato di una precedente espansione, quindi BASH lo rimuove prima di inviarlo al comando echo, ma nel 2 ° esempio, "\ *" era il risultato di una precedente espansione dei parametri, quindi NON viene rimosso. Di conseguenza, l'eco riceve "\ *" ed è quello che stampa.
Nota la differenza tra il primo esempio: "*" non è incluso nei caratteri che verranno rimossi dalla Rimozione preventivo.
Spero che abbia senso. Alla fine la conclusione è la stessa: basta usare le virgolette. Ho solo pensato di spiegare perché l'escaping, che logicamente dovrebbe funzionare se sono in gioco solo le espansioni di Parameter e Filename, non ha funzionato.
Per una spiegazione completa delle espansioni BASH, consultare:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions
Aggiungerò un po 'a questo vecchio thread.
Di solito useresti
$ echo "$FOO"
Tuttavia, ho avuto problemi anche con questa sintassi. Considera il seguente script.
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"
Le *
necessità devono essere passate alla lettera curl
, ma sorgeranno gli stessi problemi. L'esempio sopra non funzionerà (si espanderà ai nomi di file nella directory corrente) e nessuno dei due funzionerà \*
. Inoltre non puoi citare $curl_opts
perché verrà riconosciuto come una singola opzione (non valida) curl
.
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
Pertanto, consiglierei l'uso della bash
variabile $GLOBIGNORE
per impedire del tutto l'espansione del nome file se applicato al modello globale, o usare il set -f
flag incorporato.
#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1" ## no filename expansion
Applicando al tuo esempio originale:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
me$ set -f
me$ echo $FOO
BAR * BAR
me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR
SELECT * FROM etc.
, questo è l'unico modo che funziona.
echo "$FOO"
Potrebbe valere la pena prendere l'abitudine di usare printf
piuttosto che echo
dalla riga di comando.
In questo esempio non offre molti vantaggi, ma può essere più utile con output più complessi.
FOO="BAR * BAR"
printf %s "$FOO"