¿Cuál es la diferencia entre los signos iguales simples y dobles (=) en las comparaciones de shell?

¿Cuál es la diferencia entre los signos iguales simples y dobles (=) en las comparaciones de shell?

Lea que para comparar cadenas internas ifnecesitamos usar corchetes dobles. Algunos libros dicen que la comparación se puede hacer mediante =. Pero también funciona con el ==.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

¿Hay alguna diferencia entre =y ==en la comparación?

Respuesta1

En bash(como en kshdonde bashse copió esa sintaxis), [[ $a == $b ]]no es comparación, es coincidencia de patrones. Necesita [[ $a == "$b" ]]una comparación de igualdad de byte a byte. =es el mismo que ==en cualquier shell que admita [[...]].

[[...]]no es shuna sintaxis estándar. El[ dominioes estándar, y el estándarcomparaciónoperador existe =(aunque algunas [implementaciones también reconocen ==¹).

Al igual que en cualquier argumento de cualquier comando, las expansiones de variables deben citarse para evitardividir+globoy eliminación vacía (solo esta última se realiza en zsh), por lo que:

[ "$a" = "$b" ]

En estándar sh, la coincidencia de patrones se realiza con case:

case $a in
  ($b) ...
esac

Para completar, otrossimilar a la igualdadoperadores que puede encontrar en los scripts de shell:

  • [ "$a" -eq "$b" ]: [operador estándar para comparar números enteros decimales. Algunas [implementaciones permiten espacios en blanco alrededor de los números, otras permiten expresiones aritméticas arbitrarias, pero eso no es portátil. De forma portátil, se puede utilizar [ "$(($a))" -eq "$(($b))" ]para eso. Vea también [ "$((a == b))" -ne 0 ]cuál sería el equivalente estándar (excepto en POSIXly, el comportamiento solo se especifica si $acontiene $bconstantes enteras) de:

  • ((a == b)), de ksh y también encontrado en zshy bash, devuelve verdadero si la evaluación de la expresión aritmética almacenada en $aarroja el mismo número que la de $b. Normalmente, se utiliza para comparar números. Tenga en cuenta que existen variaciones entre shells en cuanto a cómo se evalúan las expresiones aritméticas y qué números se admiten (por ejemplo, bash y algunas implementaciones/versiones de ksh no admiten punto flotante ni tratan los números con ceros a la izquierda como octales).

  • expr "$a" = "$b"realiza una comparación de números si ambos operandos se reconocen como números enteros decimales (algunos permiten espacios en blanco alrededor del número) y, en caso contrario, comprueba si los dos operandos de cadena tienen el mismo orden de clasificación. También fallaría para valores de $ao $bque sean exproperadores como (, substr...

  • awk -- 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": si $ay $bse reconocen como números (al menos números decimales enteros y de coma flotante como 1.2, -1.5e-4, se ignoran los espacios en blanco iniciales y finales, algunos también reconocen hexadecimal, octal o cualquier cosa reconocida por strtod()), entonces se realiza una comparación numérica. De lo contrario, dependiendo de la implementación, es una comparación de cadenas de byte a byte, o expruna strcoll()comparación, es decir, si $aordena $blo mismo.

Ver también:


¹ que incluye GNU [y la [versión integrada de ksh, bash, yashalgunos, aunque no todos, ashshells basados ​​y zsh, sin embargo, tenga en cuenta que en zsh,=cmdes un operador de expansión de nombre de archivo especial(expandido en los mismos contextos que ~userestá) que se expande a la ruta del comando correspondiente, por lo que allí, a menos que desactive la equalsopción para deshabilitar esa característica, deberá escribirla [ "$a" '==' "$b" ]o obtendrá un error que indica que el =comando no se encuentra. Igual por[ "$string" '=~' "$regexp" ]

Respuesta2

Estos son equivalentes en bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

No es necesario citar las dos primeras variables $x. Bash realiza división de palabras y expansión de nombres de rutas dentro de [ pero no dentro de [[:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]]es una comparación de cadenas pero [[ $x = $y ]]es una expresión de coincidencia de patrones:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq solo debe usarse con números enteros:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

Ver tambiénBashFAQ/031: ¿Cuál es la diferencia entre prueba, [ y [[?.

Respuesta3

Ambos =y ==son operadores. En algunos lenguajes (como C) uno se usa para asignar un valor a una variable y el otro para comparar valores (resultado de expresiones aritméticas). De hecho, ambos operadores son exactamente eso dentro de la Evaluación Aritmética. A $((a=23))es una tarea, a $((a==23))es una comparación aritmética.

$ echo "$((a=11)) $((a==23))" "$((a=23))" "$((a==23))"
11 0 23 1

Pero dentro de las construcciones de prueba (todaspruebay[…]y[[…]]) ambos operadores pretenden significar lo mismo y realizar la misma operación.

Entonces, todas estas opciones:

test "$a" =  "$b"
   [ "$a" =  "$b" ]
  [[ "$a" =  "$b" ]]
test "$a" == "$b"
   [ "$a" == "$b" ]
  [[ "$a" == "$b" ]]

Sonequivalente en el interiorintentopara probar la igualdad binaria (variables citadas). Si la variable correcta no está entre comillas, puede interpretarse como un patrón y compararse en consecuencia: como un patrón, no como una cadena literal.

Los operadores citados \=y \==también son equivalentes cuando se usan en prueba y […]. Pero el operador citado \==falla por dentro [[…]].

Para otros shells, los resultados varían (el resultado correcto debe ser Y -(verdadero falso), un código de salida diferente de 0 (verdadero) y 1 (falso) se informa como falla con ¤). Algunos shells fallan - -(el código de salida es siempre 1).

                     | dash  ksh   bash  zsh   
  test a  =  "$b"    | Y -   Y -   Y -   Y -    
     [ a  =  "$b" ]  | Y -   Y -   Y -   Y -    
    [[ a  =  "$b" ]] | ¤ ¤   Y -   Y -   Y -    
  test a  == "$b"    | ¤ ¤   Y -   Y -   - -    
     [ a  == "$b" ]  | ¤ ¤   Y -   Y -   - -    
    [[ a  == "$b" ]] | ¤ ¤   Y -   Y -   Y -    
  test a \=  "$b"    | Y -   Y -   Y -   Y -    
     [ a \=  "$b" ]  | Y -   Y -   Y -   Y -    
    [[ a \=  "$b" ]] | ¤ ¤   Y -   - -   - -    
  test a \== "$b"    | ¤ ¤   Y -   Y -   Y -    
     [ a \== "$b" ]  | ¤ ¤   Y -   Y -   Y -    
    [[ a \== "$b" ]] | ¤ ¤   Y -   - -   - -

Todas las opciones funcionan en ksh, los operadores entrecomillados fallan en bash y zsh (dentro de [[…]]) y los operadores sin comillas \=y \==también fallan en zsh (fuera de [[…]]).

información relacionada