¿Cómo escapo del carácter comodín / asterisco en bash?

p.ej.

me$ FOO="BAR * BAR" me$ echo $FOO BAR file1 file2 file3 file4 BAR 

y usando el caracter de escape “\”:

 me$ FOO="BAR \* BAR" me$ echo $FOO BAR \* BAR 

Obviamente estoy haciendo algo estúpido.

¿Cómo obtengo la salida “BAR * BAR”?

Citar cuando se establece $ FOO no es suficiente. También debe citar la referencia de la variable:

 me$ FOO="BAR * BAR" me$ echo "$FOO" BAR * BAR 

RESPUESTA CORTA

Como han dicho otros, siempre debe citar las variables para evitar comportamientos extraños. Entonces use echo “$ foo” en lugar de solo echo $ foo .

RESPUESTA LARGA

Creo que este ejemplo merece una explicación más amplia porque hay más cosas de las que podría parecer a primera vista.

Puedo ver dónde entra tu confusión porque después de ejecutar tu primer ejemplo, probablemente pensaste que el caparazón obviamente lo está haciendo:

  1. Expansión de parámetros
  2. Extensión de nombre de archivo

Entonces desde tu primer ejemplo:

 me$ FOO="BAR * BAR" me$ echo $FOO 

Después de la expansión del parámetro es equivalente a:

 me$ echo BAR * BAR 

Y después de la expansión del nombre de archivo es equivalente a:

 me$ echo BAR file1 file2 file3 file4 BAR 

Y si simplemente escribes echo BAR * BAR en la línea de comando, verás que son equivalentes.

Así que probablemente pensó “si escapo *, puedo evitar la expansión del nombre de archivo”

Entonces desde tu segundo ejemplo:

 me$ FOO="BAR \* BAR" me$ echo $FOO 

Después de la expansión del parámetro debe ser equivalente a:

 me$ echo BAR \* BAR 

Y después de la expansión del nombre de archivo debe ser equivalente a:

 me$ echo BAR \* BAR 

Y si intenta escribir “echo BAR \ * BAR” directamente en la línea de comando, imprimirá “BAR * BAR” porque el escape evita la expansión del nombre de archivo.

Entonces, ¿por qué usar $ foo no funciona?

Es porque hay una tercera expansión que tiene lugar: Quitar eliminación. De la eliminación manual de citas bash es:

Después de las expansiones anteriores, se eliminan todas las apariciones sin comillas de los caracteres ‘\’, ” ‘y’ “‘que no resultaron de una de las expansiones anteriores.

Entonces, ¿qué ocurre cuando escribes el comando directamente en la línea de comando, el carácter de escape no es el resultado de una expansión previa, entonces BASH lo elimina antes de enviarlo al comando echo, pero en el segundo ejemplo, el “\ *” era el resultado de una expansión de parámetro anterior, por lo que NO se elimina. Como resultado, el eco recibe “\ *” y eso es lo que imprime.

Tenga en cuenta la diferencia entre el primer ejemplo – “*” no está incluido en los caracteres que se eliminarán mediante Quote Removal.

Espero que esto tenga sentido. Al final la conclusión es la misma: solo use comillas. Solo pensé en explicar por qué el escape, que lógicamente debería funcionar si solo están en juego la expansión de parámetros y nombres de archivo, no funcionó.

Para una explicación completa de las expansiones de BASH, consulte:

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions

Añadiré un poco a este viejo hilo.

Usualmente usarías

 $ echo "$FOO" 

Sin embargo, he tenido problemas incluso con esta syntax. Considere la siguiente secuencia de comandos.

 #!/bin/bash curl_opts="-s --noproxy * -O" curl $curl_opts "$1" 

El * debe pasar literalmente para curl , pero surgirán los mismos problemas. El ejemplo anterior no funcionará (se expandirá a nombres de archivo en el directorio actual) y tampoco lo hará \* . Tampoco puede citar $curl_opts porque se reconocerá como una opción única (no válida) para curl .

 curl: option -s --noproxy * -O: is unknown curl: try 'curl --help' or 'curl --manual' for more information 

Por lo tanto, recomendaría el uso de la variable bash $GLOBIGNORE para evitar la expansión del nombre del archivo si se aplica al patrón global, o usar el indicador set -f incorporado.

 #!/bin/bash GLOBIGNORE="*" curl_opts="-s --noproxy * -O" curl $curl_opts "$1" ## no filename expansion 

Aplicando a su ejemplo original:

 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" 

Puede valer la pena adquirir el hábito de usar printf lugar de echo en la línea de comando.

En este ejemplo, no ofrece muchos beneficios, pero puede ser más útil con resultados más complejos.

 FOO="BAR * BAR" printf %s "$FOO"