Primero, separe zsh del resto. No se trata de conchas antiguas versus modernas: zsh se comporta de manera diferente. Los diseñadores de zsh decidieron hacerlo incompatible con los shells tradicionales (Bourne, ksh, bash), pero más fáciles de usar.
En segundo lugar, es mucho más fácil usar comillas dobles todo el tiempo que recordar cuándo son necesarias. Se necesitan la mayor parte del tiempo, por lo que deberá aprender cuándo no se necesitan, no cuando se necesitan.
En pocas palabras, las comillas dobles son necesarias donde se espera una lista de palabras o un patrón . Son opcionales en contextos donde el analizador espera una cadena sin formato.
Que pasa sin comillas
Tenga en cuenta que sin comillas dobles, suceden dos cosas.
- Primero, el resultado de la expansión (el valor de la variable para una sustitución de parámetro como
${foo}
, o la salida del comando para una sustitución de comando como $(foo)
) se divide en palabras donde contiene espacios en blanco.
Más precisamente, el resultado de la expansión se divide en cada carácter que aparece en el valor de la IFS
variable (carácter separador). Si una secuencia de caracteres separadores contiene espacios en blanco (espacio, tabulación o nueva línea), el espacio en blanco se cuenta como un solo carácter; Los separadores iniciales, finales o repetidos que no son espacios en blanco conducen a campos vacíos. Por ejemplo, con IFS=" :"
, :one::two : three: :four
produce campos vacíos antes one
, entre one
y two
, y (uno solo) entre three
y four
.
- Cada campo que resulta de la división se interpreta como un globo (un patrón comodín) si contiene uno de los caracteres
\[*?
. Si ese patrón coincide con uno o más nombres de archivo, el patrón se reemplaza por la lista de nombres de archivo coincidentes.
Una expansión de variable sin comillas $foo
se conoce coloquialmente como el "operador split + glob", en contraste con el "$foo"
cual solo toma el valor de la variable foo
. Lo mismo ocurre con la sustitución de comandos: "$(foo)"
es una sustitución de comandos, $(foo)
es una sustitución de comandos seguida de split + glob.
Donde puedes omitir las comillas dobles
Estos son todos los casos en los que puedo pensar en un shell de estilo Bourne donde puede escribir una variable o una sustitución de comando sin comillas dobles, y el valor se interpreta literalmente.
En el lado derecho de una tarea.
var=$stuff
a_single_star=*
Tenga en cuenta que necesita las comillas dobles después export
, porque es una construcción ordinaria, no una palabra clave. Esto solo es cierto en algunos shells como dash, zsh (en emulación sh), yash o posh; bash y ksh ambos tratan export
especialmente.
export VAR="$stuff"
En un case
comunicado.
case $var in …
Tenga en cuenta que necesita comillas dobles en un patrón de caso. La división de palabras no ocurre en un patrón de caso, pero una variable sin comillas se interpreta como un patrón, mientras que una variable entre comillas se interpreta como una cadena literal.
a_star='a*'
case $var in
"$a_star") echo "'$var' is the two characters a, *";;
$a_star) echo "'$var' begins with a";;
esac
Entre corchetes dobles. Los corchetes dobles son una sintaxis especial de shell.
[[ -e $filename ]]
Excepto que necesita comillas dobles donde se espera un patrón o una expresión regular: en el lado derecho de =
or ==
o !=
or =~
.
a_star='a*'
if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
fi
Necesita comillas dobles como de costumbre entre corchetes simples [ … ]
porque son una sintaxis de shell ordinaria (es un comando que se llama [
). Ver paréntesis simples o dobles
En una redirección en shells POSIX no interactivos (no bash
, ni ksh88
).
echo "hello world" >$filename
Algunos shells, cuando son interactivos, tratan el valor de la variable como un patrón comodín. POSIX prohíbe ese comportamiento en shells no interactivos, pero algunos shells como bash (excepto en el modo POSIX) y ksh88 (incluso cuando se encuentran como (supuestamente) POSIX sh
de algunos Unices comerciales como Solaris) todavía lo hacen allí ( bash
también intenta dividir y la redirección falla a menos que divididos + englobamiento resultados en exactamente una palabra), por lo que es mejor para citar a los objetivos de redirecciones en una sh
secuencia de comandos en caso de que quiera convertirlo en un bash
guión algún día, o ejecutarlo en un sistema en el que sh
está no cumple con ese punto, o puede provenir de shells interactivos.
Dentro de una expresión aritmética. De hecho, debe dejar las comillas para que una variable se analice como una expresión aritmética.
expr=2*2
echo "$(($expr))"
Sin embargo, necesita las comillas alrededor de la expansión aritmética, ya que están sujetas a la división de palabras en la mayoría de los shells según lo requiera POSIX (!?).
En un subíndice de matriz asociativa.
typeset -A a
i='foo bar*qux'
a[foo\ bar\*qux]=hello
echo "${a[$i]}"
Una sustitución de comando y variable sin comillas puede ser útil en algunas circunstancias poco frecuentes:
- Cuando el valor variable o la salida del comando consta de una lista de patrones globales y desea expandir estos patrones a la lista de archivos coincidentes.
- Cuando sabe que el valor no contiene ningún carácter comodín, eso
$IFS
no se modificó y desea dividirlo en caracteres de espacio en blanco.
- Cuando desee dividir un valor en un determinado carácter: desactive el globbing con
set -f
, establezca IFS
el carácter separador (o déjelo solo para dividir en espacios en blanco), luego realice la expansión.
Zsh
En zsh, puede omitir las comillas dobles la mayoría de las veces, con algunas excepciones.
$var
nunca se expande a varias palabras, sin embargo, se expande a la lista vacía (a diferencia de una lista que contiene una sola palabra vacía) si el valor de var
es la cadena vacía. Contraste:
var=
print -l $var foo # prints just foo
print -l "$var" foo # prints an empty line, then foo
Del mismo modo, se "${array[@]}"
expande a todos los elementos de la matriz, mientras que $array
solo se expande a los elementos no vacíos.
La @
bandera de la expansión de parámetros a veces requiere comillas dobles alrededor de toda la substitución: "${(@)foo}"
.
La sustitución de comandos sufre división de campo si no está entre comillas: echo $(echo 'a'; echo '*')
imprime a *
(con un solo espacio) mientras que echo "$(echo 'a'; echo '*')"
imprime la cadena de dos líneas no modificada. Utilícelo "$(somecommand)"
para obtener la salida del comando en una sola palabra, sin líneas nuevas finales. Utilícelo "${$(somecommand; echo _)%?}"
para obtener el resultado exacto del comando, incluidas las nuevas líneas finales. Use "${(@f)$(somecommand)}"
para obtener una matriz de líneas de la salida del comando.
SH_WORD_SPLIT
opción.