¿Cuál es la diferencia entre [[$ a == z *]] y [$ a == z *]?

35

¿Hay alguna diferencia entre estos dos?

[[ $a == z* ]]

y

[ $a == z* ] 

¿Puedo tener un ejemplo donde tendrían diferentes salidas?

Además, ¿en qué [[ ]]difiere el funcionamiento de [ ]?

munish
fuente

Respuestas:

41

La diferencia entre [[ … ]]y [ … ]se cubre principalmente con el uso de corchetes simples o dobles: bash . Crucialmente, [[ … ]]es una sintaxis especial, mientras que [es un nombre divertido para un comando. [[ … ]]tiene reglas de sintaxis especiales para lo que hay dentro, [ … ]no.

Con la arruga agregada de un comodín, así [[ $a == z* ]]es como se evalúa:

  1. Analiza el comando: esta es la [[ … ]]construcción condicional alrededor de la expresión condicional $a == z*.
  2. Analiza la expresión condicional: este es el ==operador binario, con los operandos $ay z*.
  3. Expanda el primer operando en el valor de la variable a.
  4. Evalúe el ==operador: pruebe si el valor de la variable acoincide con el patrón z*.
  5. Evaluar la expresión condicional: su resultado es el resultado del operador condicional.
  6. El comando ahora se evalúa, su estado es 0 si la expresión condicional era verdadera y 1 si era falsa.

Así [ $a == z* ]se evalúa:

  1. Analizar el comando: este es el [comando con los argumentos formados mediante la evaluación de las palabras $a, ==, z*, ].
  2. Expandir $aen el valor de la variable a.
  3. Realice la división de palabras y la generación de nombre de archivo en los parámetros del comando.
    • Por ejemplo, si el valor de aes la cadena de 6 caracteres foo b*(obtenida por ejemplo a='foo b*') y la lista de archivos en el directorio actual es ( bar, baz, qux, zim, zum), entonces el resultado de la expansión es la siguiente lista de palabras: [, foo, bar, baz, ==, zim, zum, ].
  4. Ejecute el comando [con los parámetros obtenidos en el paso anterior.
    • Con los valores de ejemplo anteriores, el [comando se queja de un error de sintaxis y devuelve el estado 2.

Nota: En el [[ $a == z* ]]paso 3, el valor de ano sufre división de palabras y generación de nombre de archivo, porque es en un contexto donde se espera una sola palabra (el argumento de la izquierda del operador condicional ==). En la mayoría de los casos, si una sola palabra tiene sentido en esa posición, la expansión variable se comporta como en comillas dobles. Sin embargo, hay una excepción a esa regla: en [[ abc == $a ]], si el valor de acontiene comodines, entonces ase compara con el patrón de comodines. Por ejemplo, si el valor de aes a*entonces [[ abc == $a ]]que es verdadero (porque el comodín *procedentes de la expansión no cotizado de $apartidos *), mientras que [[ abc == "$a" ]]es falso (debido a que el carácter ordinario*proveniente de la expansión citada de $ano coincide bc). En el interior [[ … ]], las comillas dobles no hacen una diferencia, excepto en el lado derecho de los operadores de cadena coincidente ( =, ==, !=y =~).

Gilles 'SO- deja de ser malvado'
fuente
39

[es un alias para el testcomando. La versión 6 de Unix tenía un ifcomando, pero la versión 7 (1979) vino con el nuevo shell Bourne que tenía algunas construcciones de programación, incluida la construcción if-then-else-elif-fi, y la versión 7 de Unix agregó un testcomando que realizaba la mayor parte de "pruebas" realizadas por el ifcomando en versiones anteriores.

[se hizo un alias testy ambos se construyeron en el shell en Unix System III (1981) . Aunque debe tenerse en cuenta que algunas variantes de Unix no tuvieron un [comando hasta mucho después ( hasta principios de la década de 2000 en algunos BSD donde shse basa en el shell Almquist ( testsiempre se ha incluido ashuna fuente incorporada en la fuente, pero en esos BSDs fue inicialmente deshabilitado)).

Tenga en cuenta que testaka [es un comando para hacer "pruebas", no hay asignación que haga ese comando, por lo que no hay razón para desambiguar entre una asignación y un operador de igualdad, por lo que el operador de igualdad sí lo es =. ==solo es compatible con algunas implementaciones recientes de [(y es solo un alias para =).

Como [no es más que un comando, el shell lo analiza de la misma manera que cualquier otro comando.

Específicamente, en su ejemplo, $adebido a que no se cita, se dividiría en varias palabras de acuerdo con las reglas habituales de división de palabras, y cada palabra se sometería a la generación de nombre de archivo, también conocido como globbing, para dar como resultado posiblemente más palabras, resultando cada una de esas palabras en Un argumento separado para el [comando.

Del mismo modo, z*se expandiría a la lista de nombres de archivo en el directorio actual que comienza con z.

Entonces, por ejemplo, si $aes b* = x, y hay z1,z2 , b1y b2los archivos en el directorio actual, el [comando sería conseguir 9 argumentos: [, b1, b2, =, x, ==, z1, z2y ].

[analiza sus argumentos como una expresión condicional. Esos 9 argumentos no se suman a una expresión condicional válida, por lo que probablemente devolverá un error.

La [[ ... ]]construcción fue introducida por el caparazón de Korn probablemente alrededor de 1988, ya que ksh86aen 1987 no la tenía mientras la ksh88tenía desde el principio.

Además de ksh (todas las implementaciones), [[...]]también es compatible con bash (desde la versión 2.02) y zsh, pero las tres implementaciones son diferentes y existen diferencias entre cada versión de un mismo shell, aunque los cambios son generalmente compatibles con versiones anteriores (una notable excepción es bash =~operador que se sabe que rompe algunos scripts después de una determinada versión cuando su comportamiento cambió). [[...]]no está especificado por POSIX, Unix o Linux (LSB). Se ha considerado su inclusión varias veces, pero no se ha incluido ya que la funcionalidad común de la misma soportada por los shells principales ya está cubierta por el [comando y la case-in-esacconstrucción.

Toda la [[ ... ]]construcción constituye un comando. Es decir, tiene un estado de salida (que es su activo más importante ya que es el resultado de evaluar la expresión condicional), puede canalizarlo a otro comando (aunque no sería útil) y, en general, usarlo donde quiera use cualquier otro comando (solo dentro del shell, ya que es una construcción de shell) pero no se analiza como un comando simple normal. El shell analiza lo que hay dentro como una expresión condicional y las reglas habituales de división de palabras y generación de nombre de archivo se aplican de manera diferente.

[[ ... ]]sabe ==desde el principio y es equivalente a= 1 . Sin embargo, un error de ksh (y está causando confusión y muchos errores) es que =y ==no son un operador de igualdad sino un operador de coincidencia de patrones (aunque el aspecto de coincidencia se puede deshabilitar con comillas pero con reglas poco claras que difieren de shell a shell).

En su código anterior [[ $a == z* ]], el shell lo analizaría en varios tokens en reglas similares a las habituales, lo reconocería como una comparación de coincidencia de patrones, lo trataría z*como un patrón para comparar con el contenido de la avariable.

En general, es más difícil dispararte en el pie con [[ ... ]] que con el [comando. Pero algunas reglas como

  • siempre cotizar variables
  • nunca use el operador -ao -o(use varios [comandos y el &&y|| operadores shell )

Hacer [ confiable con los proyectiles POSIX.

[[...]] en diferentes shells admiten operadores adicionales como -nt , operadores de coincidencia de expresiones regulares ... pero la lista y el comportamiento varían de un shell a otro y de una versión a otra.

Entonces, a menos que sepa con qué shell y versión mínima se interpretará su script, probablemente sea más seguro seguir con el [comando estándar .


1 Una excepción: [[...]]se agregó a bash en la versión 2.02. Hasta 2.03donde fue cambiado, [[ x = '?' ]]volvería verdadero mientras [[ x == '?' ]]que volvería falso. Es decir, las citas no impidieron la coincidencia de patrones cuando se usaba el =operador en esas versiones, pero sí cuando se usaba ==.

Stéphane Chazelas
fuente
Gran información ¿Podría explicar por qué "nunca use el operador -a o -o"?
grebneke
@grebneke, tratar [ '!' = foo -o a = a ]de bash, por ejemplo.
Stéphane Chazelas
0

ambos se utilizan para evaluar expresiones y [[no funcionará con POSIX shell bourn más antiguo y [[también admite coincidencia de patrones y expresiones regulares. ejemplo prueba estos

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"

harish.venkat
fuente
Tenga en cuenta que el shell Bourne no es POSIX, [[...]]solo admite expresiones regulares en algunas versiones de algunos shells, al igual que algunas versiones de [sí admiten la coincidencia de expresiones regulares . Para una comparación aritmética, en esos proyectiles que lo apoyan [[, preferiría escribir(( n == 0 && y == 0))
Stéphane Chazelas el