2008-09-19 12 views

Respuesta

96

Citando a la hora de establecer $ FOO no es suficiente. Es necesario citar la variable de referencia, así:

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

esto es misterioso, ¿por qué es esto? ¿Que esta pasando? – tofutim

3
FOO='BAR * BAR' 
echo "$FOO" 
+0

Esto funciona, pero no es esencial para cambiar las comillas simples en la primera línea de comillas dobles. – finnw

+1

No, no lo es, pero el hábito de usar comillas simples es preferible cuando va a incluir caracteres de shell especiales y no desea ninguna sustitución. – tzot

3
echo "$FOO" 
3

Puede valer la pena entrar en el hábito de usar en lugar de printfecho en la línea de comandos.

En este ejemplo no da mucho beneficio pero puede ser más útil con una producción más compleja.

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

¿Por qué diablos? printf es un proceso separado (al menos, no incorporado en bash) y el uso de printf que usted demuestra no tiene ningún beneficio sobre el eco. – ddaa

+1

printf * es * un bash incorporado y lo dije en mi respuesta "En este ejemplo no da mucho beneficio pero puede ser más útil con resultados más complejos. –

73

RESPUESTA CORTA

Como otros han dicho - siempre hay que citar las variables para evitar un comportamiento extraño. Así que utilice echo "$ foo" en lugar de sólo echo $ foo.

respuesta larga

yo creo este ejemplo merece mayor explicación porque hay más en juego de lo que parece en la cara de ella.

puedo ver dónde está su confusión viene adentro porque después de ejecutar el primer ejemplo que probablemente pensó a sí mismo que la cáscara está haciendo obvio:

  1. expansión de parámetros
  2. expansión Nombre

por lo que desde su primer ejemplo:

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

Un espués de la expansión de parámetro es equivalente a:

me$ echo BAR * BAR 

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

me$ echo BAR file1 file2 file3 file4 BAR 

Y si sólo tiene que teclear echo BAR * BAR en la línea de comando que va a ver que son equivalentes.

Así que probablemente pensado a sí mismo "si me escape el *, puedo evitar que la expansión de nombre de archivo"

Así que a partir de su segundo ejemplo:

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

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

me$ echo BAR \* BAR 

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

me$ echo BAR \* BAR 

Y si intenta escribir "echo BAR \ * BAR" directamente en la línea de comandos, imprimirá "BAR * BAR" porque la expansión del nombre de archivo se previene con el escape.

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

Es porque hay una tercera expansión que tiene lugar - Quitar la eliminación. A partir de la extracción manual cotización Bash es:

Después de las expansiones anteriores, todos los ocurrencias no cotizados de los personajes '\', ''', y '"' que no resultaron de una de las expansiones anteriores son eliminado.

así que lo que sucede es cuando se escribe el comando directamente en la línea de comandos, el carácter de escape no es el resultado de una expansión previa de modo BASH lo elimina antes de enviarlo al comando de eco, pero en el segundo ejemplo, el "\ *" fue 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 que la diferencia entre el primer ejemplo - "*" no está incluida 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 Bash, se refieren a:

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

+0

¡Excelente respuesta! Ahora no lo siento preguntó una pregunta tan tonta. :-) – andyuk

+1

Existe alguna utilidad para escapar de los caracteres especiales? –

+0

"siempre debe citar las variables para evitar el comportamiento extraño" - cuando desea utilizarlos como cadenas – Angelo

37

Voy a añadir un poco a este viejo hilo.

Normalmente se usaría

$ echo "$FOO" 

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

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

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

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

Por lo tanto, recomiendo el uso de la variable bash$GLOBIGNORE para prevenir la expansión de nombre de archivo completo si aplica al patrón global, o utilizar el set -f incorporada bandera.

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

Aplicando a su original ejemplo:

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 
+2

Solo 'set -f' funcionó en mi caso –

+2

¡Gran explicación, gracias! Mi uso es' SELECT * FROM etc.', esto es la única forma que funciona. – knutole

+0

Gracias por presentar la solución set -f! – hachre

Cuestiones relacionadas