El viejo consejo solía ser citar dos veces cualquier expresión que involucrara un $VARIABLE
, al menos si uno quisiera que el intérprete lo interpretara como un solo elemento, de lo contrario, cualquier espacio en el contenido de $VARIABLE
arrojaría el intérprete.
Sin embargo, entiendo que en versiones más recientes de shells, las comillas dobles ya no siempre son necesarias (al menos para el propósito descrito anteriormente). Por ejemplo, en bash
:
% FOO='bar baz'
% [ $FOO = 'bar baz' ] && echo OK
bash: [: too many arguments
% [[ $FOO = 'bar baz' ]] && echo OK
OK
% touch 'bar baz'
% ls $FOO
ls: cannot access bar: No such file or directory
ls: cannot access baz: No such file or directory
En zsh
, por otro lado, los mismos tres comandos tienen éxito. Por lo tanto, en base a este experimento, parece que, en bash
, uno puede omitir las comillas dobles en el interior [[ ... ]]
, pero no en el interior [ ... ]
ni en los argumentos de la línea de comandos, mientras que, en zsh
, estos pueden omitirse en todos estos casos.
Pero inferir reglas generales a partir de ejemplos anecdóticos como el anterior es una propuesta arriesgada. Sería bueno ver un resumen de cuándo es necesaria una doble cita. Estoy interesado principalmente en zsh
, bash
y /bin/sh
.
SH_WORD_SPLIT
opción.Respuestas:
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.
${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, conIFS=" :"
,:one::two : three: :four
produce campos vacíos antesone
, entreone
ytwo
, y (uno solo) entrethree
yfour
.\[*?
. 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 variablefoo
. 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.
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 tratanexport
especialmente.En un
case
comunicado.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.
Entre corchetes dobles. Los corchetes dobles son una sintaxis especial de shell.
Excepto que necesita comillas dobles donde se espera un patrón o una expresión regular: en el lado derecho de
=
or==
o!=
or=~
.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 doblesEn una redirección en shells POSIX no interactivos (no
bash
, niksh88
).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 unash
secuencia de comandos en caso de que quiera convertirlo en unbash
guión algún día, o ejecutarlo en un sistema en el quesh
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.
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.
Una sustitución de comando y variable sin comillas puede ser útil en algunas circunstancias poco frecuentes:
$IFS
no se modificó y desea dividirlo en caracteres de espacio en blanco.set -f
, establezcaIFS
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 devar
es la cadena vacía. Contraste: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 '*')
imprimea *
(con un solo espacio) mientras queecho "$(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.fuente
echo "$(("$expr"))"
man bash
dice: la expresión se trata como si estuviera entre comillas dobles, pero una comilla doble entre paréntesis no se trata especialmente.echo
. Puede valer la pena intentar que el lenguaje sea aún más explícito (¿"cuando el analizador espera una cadena sin procesar", quizás?)