GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cuándo son necesarias las comillas dobles?

El viejo consejo solía ser poner entre comillas dobles cualquier expresión que involucre un $VARIABLE , al menos si uno quisiera que el shell lo interpretara como un solo elemento; de lo contrario, cualquier espacio en el contenido de $VARIABLE arrojaría el caparazón.

Entiendo, sin embargo, 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, según este experimento, parece que, en bash , se pueden omitir las comillas dobles dentro de [[ ... ]] , pero no dentro de [ ... ] ni en argumentos de línea de comandos, mientras que en zsh , las comillas dobles 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 son necesarias las comillas dobles. Estoy principalmente interesado en zsh , bash y /bin/sh .

Respuesta aceptada:

Primero, separe zsh del resto. No es una cuestión de shells antiguos o modernos: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ácil de usar.

En segundo lugar, es mucho más fácil usar comillas dobles todo el tiempo que recordar cuándo se necesitan. 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 siempre que se espera una lista de palabras o un patrón . Son opcionales en contextos donde el analizador espera una cadena sin formato.

Qué sucede sin comillas

Tenga en cuenta que sin comillas dobles, suceden dos cosas.

  1. 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 dondequiera que contenga espacios en blanco.
    Más precisamente, el resultado de la expansión se divide en cada carácter que aparece en el valor del IFS variable (carácter separador). Si una secuencia de caracteres separadores contiene espacios en blanco (espacio, tabulador o nueva línea), el espacio en blanco cuenta como un solo carácter; los separadores que no son espacios en blanco al principio, al final o repetidos conducen a campos vacíos. Por ejemplo, con IFS=" :" , :one::two : three: :four  produce campos vacíos antes de one , entre one y two , y (uno solo) entre three y four .
  2. 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 archivos, el patrón se reemplaza por la lista de nombres de archivos coincidentes.

Una expansión variable sin comillas $foo se conoce coloquialmente como el "operador split+glob", en contraste con "$foo" que simplemente toma el valor de la variable foo . Lo mismo ocurre con la sustitución de comandos:"$(foo)" es una sustitución de comando, $(foo) es una sustitución de comando seguida de split+glob.

Donde puede 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 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 de export , porque es un componente ordinario, no una palabra clave. Esto solo es cierto en algunos shells como dash, zsh (en emulación sh), yash o posh; bash y ksh tratan ambos export especialmente.

    export VAR="$stuff"
    
  • En un case declaración.

    case $var in …
    

    Tenga en cuenta que necesita comillas dobles en un patrón de mayúsculas y minúsculas. La división de palabras no ocurre en un patrón de mayúsculas y minúsculas, 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
    
  • Dentro de corchetes dobles. Los corchetes dobles son 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 = o == o != o =~ .

    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 sintaxis de shell ordinarias (es un comando que se llama [ ). Ver Corchetes 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 incluyen bash (excepto en 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 split+globbing da como resultado exactamente una palabra), por lo que es mejor citar los objetivos de las redirecciones en un sh script en caso de que quieras convertirlo en un bash script algún día, o ejecútelo en un sistema donde sh no cumple con ese punto, o puede ser fuente de conchas interactivas.

  • Dentro de una expresión aritmética. De hecho, debe omitir 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, como lo requiere POSIX (!?).

  • En un subíndice de matriz asociativa.

    typeset -A a
    i='foo bar*qux'
    a[foo bar*qux]=hello
    echo "${a[$i]}"
    

Una variable sin comillas y una sustitución de comando pueden ser útiles en algunas circunstancias excepcionales:

  • Cuando el valor de la 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, $IFS no se modificó y desea dividirlo en caracteres de espacio en blanco.
  • Cuando desee dividir un valor en un determinado carácter:deshabilite el globbing con set -f , establecer IFS al carácter separador (o déjelo solo para dividir en espacios en blanco), luego haga la expansión.
Relacionado:¿Por qué usar intercambio cuando hay espacio libre más que suficiente en la RAM?

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, "${array[@]}" se expande a todos los elementos de la matriz, mientras que $array solo se expande a los elementos no vacíos.

  • El @ la bandera de expansión del parámetro a veces requiere comillas dobles alrededor de toda la sustitución:"${(@)foo}" .

  • La sustitución de comandos se divide en 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 sin modificar. Usa "$(somecommand)" para obtener el resultado del comando en una sola palabra, sin saltos de línea finales. Usa "${$(somecommand; echo _)%?}" para obtener el resultado exacto del comando, incluidas las nuevas líneas finales. Utilice "${(@f)$(somecommand)}" para obtener una matriz de líneas de la salida del comando.

Relacionado:typeset -A está dando un error en el script?
Linux
  1. ¿Por qué la tilde (~) no se expande dentro de comillas dobles?

  2. ¿Comodines dentro de las comillas?

  3. ¿Envolviendo un comando que incluye comillas simples y dobles para otro comando?

  4. ¿Cuándo usar Nohup?

  5. ¿Qué es un buen mnemotécnico para Shell Double vs. ¿Comillas simples?

¿Por qué se muestra una sola barra invertida cuando se usan comillas?

¿Agregar comillas dobles alrededor de los campos en la salida del script AWK?

Al configurar IFS para que se divida en saltos de línea, ¿por qué es necesario incluir un retroceso?

¿Cuándo es necesario reiniciar?

como quitar las comillas dobles en un csv

Reemplazo de guión bajo por coma y eliminación de comillas dobles en CSV