En resumen, cite todo lo que no requiera que el shell realice la división de tokens y la expansión de comodines.
Las comillas simples protegen el texto entre ellas al pie de la letra. Es la herramienta adecuada cuando necesitas asegurarte de que el caparazón no toque la cuerda en absoluto. Por lo general, es el mecanismo de cotización de elección cuando no requiere interpolación variable.
$ echo 'Nothing \t in here $will change'
Nothing \t in here $will change
$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.
Las comillas dobles son adecuadas cuando se requiere interpolación variable. Con las adaptaciones adecuadas, también es una buena solución cuando necesita comillas simples en la cadena. (No hay manera fácil de escapar de una comilla entre comillas simples, porque no hay ningún mecanismo de escape entre comillas simples - si había, ellos no citan textualmente por completo.)
$ echo "There is no place like '$HOME'"
There is no place like '/home/me'
sin comillas son adecuados cuando específicamente requiere que el intérprete de comandos realice la división de tokens y/o la expansión de comodines.
División de tokens;
$ words="foo bar baz"
$ for word in $words; do
> echo "$word"
> done
foo
bar
baz
Por el contrario:
$ for word in "$words"; do echo "$word"; done
foo bar baz
(El bucle sólo se ejecuta una vez, a lo largo de la cadena única, citado.)
$ for word in '$words'; do echo "$word"; done
$words
(El bucle sólo se ejecuta una vez, más de lo literal sola -cinta citada.)
expansión comodín:
$ pattern='file*.txt'
$ ls $pattern
file1.txt file_other.txt
Por el contrario:
$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory
(no hay un archivo llamado literalmente file*.txt
.)
$ ls '$pattern'
ls: cannot access $pattern: No such file or directory
(no hay un archivo llamado $pattern
, ya sea!)
En términos más concretos, cualquier cosa que contenga un nombre de archivo por lo general debe ser citado (porque los nombres de archivo pueden contener espacios en blanco y otros metacaracteres de shell). Cualquier cosa que contenga una URL generalmente se debe citar (porque muchas URL contienen metacaracteres del shell como ?
y &
). Cualquier cosa que contenga una expresión regular debería ser citada (ídem ídem). Se debe citar todo lo que contenga espacios en blanco significativos que no sean espacios únicos entre caracteres que no sean espacios en blanco (porque, de lo contrario, el shell afectará espacios en blanco, efectivamente, espacios únicos y recortará cualquier espacio en blanco inicial o posterior).
Cuando sabe que una variable solo puede contener un valor que no contiene metacaracteres del shell, las citas son opcionales. Por lo tanto, un $?
sin comillas es básicamente correcto, ya que esta variable solo puede contener un solo número. Sin embargo, "$?"
también es correcto y se recomienda para la coherencia general y la corrección (aunque esta es mi recomendación personal, no una política ampliamente reconocida).
Los valores que no son variables básicamente siguen las mismas reglas, aunque también podría escapar de cualquier metacaracteres en lugar de citarlos. Para un ejemplo común, una URL con un &
en ella será analizado por la concha como un comando de fondo a menos que el metacarácter se escapó o citado:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
(Por supuesto, esto también ocurre si la URL está en una variable sin comillas). Para una cadena estática, las comillas simples tienen más sentido, aunque cualquier forma de cita o escape funciona aquí.
wget 'http://example.com/q&uack' # Single quotes preferred for a static string
wget "http://example.com/q&uack" # Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack # Backslash escape
wget http://example.com/q'&'uack # Only the metacharacter really needs quoting
El último ejemplo también sugiere otro concepto útil, que me gusta llamar "cesa de cotización". Si necesita mezclar comillas simples y dobles, puede usarlas adyacentes entre sí. Por ejemplo, las siguientes cadenas
'$HOME '
"isn't"
' where `<3'
"' is."
citados se pueden pegar juntas espalda con espalda, formando una sola cadena larga después de tokenización y la cita de eliminación.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Esto no es muy legible, pero es una técnica común y, por tanto, es bueno saberlo.
Como un lado, scripts should usually not use ls
for anything. Para expandir un comodín, simplemente ... úselo.
$ printf '%s\n' $pattern # not ``ls -1 $pattern''
file1.txt
file_other.txt
$ for file in $pattern; do # definitely, definitely not ``for file in $(ls $pattern)''
> printf 'Found file: %s\n' "$file"
> done
Found file: file1.txt
Found file: file_other.txt
(El bucle es totalmente superflua en el último ejemplo;. printf
trabaja específicamente bien con múltiples argumentos stat
también Pero bucle durante un partido comodín es un problema común, y con frecuencia se hace incorrectamente..)
Una variable que contiene una lista de tokens para repetir o un comodín para expandirse se ve con menos frecuencia, por lo que a veces abreviamos para "citar todo a menos que sepa exactamente lo que está haciendo".
No hay preguntas tontas. Bueno, hay _are, _ pero este no es uno de ellos :-) – paxdiablo
Véase también http://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable- in-bash-posix-shells – tripleee
Esta pregunta recibe muchos duplicados, muchos de los cuales no son sobre variables, así que retitulé a "valor" en lugar de "variable". Espero que esto ayude a más personas a encontrar este tema. – tripleee