Come posso evitare il carattere jolly / asterisco in bash?
Domanda
ad es.
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
e usando " \ " carattere di escape:
me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR
Ovviamente sto facendo qualcosa di stupido.
Come posso ottenere l'output " BAR * BAR " ?
Soluzione
Citare quando si imposta $ FOO non è sufficiente. Devi citare anche il riferimento alla variabile:
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
Altri suggerimenti
RISPOSTA CORTA
Come altri hanno già detto, dovresti sempre citare le variabili per evitare 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 quello che potrebbe sembrare in faccia.
Posso vedere da dove viene la tua confusione perché dopo aver eseguito il tuo primo esempio probabilmente hai pensato a te stesso che la shell ovviamente sta facendo:
- Espansione dei parametri
- Espansione nome file
Quindi dal tuo primo esempio:
me$ FOO="BAR * BAR"
me$ echo $FOO
Dopo 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 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:
<*>E se provi a digitare " echo BAR \ * BAR " direttamente nella riga di comando verrà effettivamente stampato "BAR * BAR" perché l'espansione del nome file è impedita dall'escape.
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 precedenti espansioni, tutto ricorrenze non quotate dei personaggi "\", "" E """ che non hanno prodotto risultati da una delle espansioni di cui sopra sono rimosso.
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 secondo esempio, il " \ * " era il risultato di una precedente espansione dei parametri, quindi NON è stato 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 / manuale / bashref.html # Shell-Espansioni
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"
*
deve essere passato letteralmente a curl
, ma sorgeranno gli stessi problemi. L'esempio sopra non funzionerà (si espanderà ai nomi di file nella directory corrente) e nemmeno \ *
. Inoltre non puoi citare $ curl_opts
perché sarà riconosciuto come una singola opzione (non valida) per curl
.
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
Pertanto, raccomanderei l'uso della variabile bash
$ GLOBIGNORE
per impedire del tutto l'espansione del nome file se applicato al modello globale, oppure usare set -f
bandiera integrata.
#!/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
FOO='BAR * BAR'
echo "$FOO"
echo "$FOO"
Potrebbe valere la pena prendere l'abitudine di usare printf
anziché echo
sulla 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"