Respuestas:
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:
[[ … ]]
construcción condicional alrededor de la expresión condicional $a == z*
.==
operador binario, con los operandos $a
y z*
.a
.==
operador: pruebe si el valor de la variable a
coincide con el patrón z*
.Así [ $a == z* ]
se evalúa:
[
comando con los argumentos formados mediante la evaluación de las palabras $a
, ==
, z*
, ]
.$a
en el valor de la variable a
.a
es 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
, ]
.[
con los parámetros obtenidos en el paso anterior.
[
comando se queja de un error de sintaxis y devuelve el estado 2.Nota: En el [[ $a == z* ]]
paso 3, el valor de a
no 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 a
contiene comodines, entonces a
se compara con el patrón de comodines. Por ejemplo, si el valor de a
es a*
entonces [[ abc == $a ]]
que es verdadero (porque el comodín *
procedentes de la expansión no cotizado de $a
partidos *
), mientras que [[ abc == "$a" ]]
es falso (debido a que el carácter ordinario*
proveniente de la expansión citada de $a
no coincide bc
). En el interior [[ … ]]
, las comillas dobles no hacen una diferencia, excepto en el lado derecho de los operadores de cadena coincidente ( =
, ==
, !=
y =~
).
[
es un alias para el test
comando. La versión 6 de Unix tenía un if
comando, 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 test
comando que realizaba la mayor parte de "pruebas" realizadas por el if
comando en versiones anteriores.
[
se hizo un alias test
y 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 sh
se basa en el shell Almquist ( test
siempre se ha incluido ash
una fuente incorporada en la fuente, pero en esos BSDs fue inicialmente deshabilitado)).
Tenga en cuenta que test
aka [
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, $a
debido 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 $a
es b* = x
, y hay z1
,z2
, b1
y b2
los archivos en el directorio actual, el [
comando sería conseguir 9 argumentos: [
, b1
, b2
, =
, x
, ==
, z1
, z2
y ]
.
[
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 ksh86a
en 1987 no la tenía mientras la ksh88
tení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-esac
construcció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 a
variable.
En general, es más difícil dispararte en el pie con [[ ... ]]
que con el [
comando. Pero algunas reglas como
-a
o -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.03
donde 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 ==
.
[ '!' = foo -o a = a ]
de bash
, por ejemplo.
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"
[[...]]
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))