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

28

Lea que para comparar cadenas en el interior ifnecesitamos usar corchetes dobles. Algunos libros dicen que la comparación se puede hacer por =. 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?

usuario3539
fuente
44
¿Hay alguna pregunta aquí en alguna parte? Si es así, no lo estoy viendo. =es para [. ==es para [[.
Chris Down
@ChrisDown Eso no es del todo cierto.
xdavidliu
@xdavidliu ¿Quieres elaborar? Ciertamente es cierto de acuerdo con POSIX, que no comprende ==, por lo que debería usar =(igualdad) con [, y ==(coincidencia de patrones, con semántica que son comillas) [[. Ver help testvs help [[.
Chris Down
@ChrisDown tal vez estoy malinterpretando lo que significa "es para". Si "es para" significa "solo funciona con", entonces el comentario no es verdadero, ya que [ foo == foo ] && echo foociertamente se imprime foo, lo que indica que ==funciona con [. Sin embargo, si por "es para" quieres decir "estaba destinado a ser usado con", entonces tengo una menor objeción.
xdavidliu
@xdavidliu "es para" en el caso específico que está mencionando significa "está definido por POSIX". El hecho de fiesta pasa a aceptarlo como la comodidad, no significa que es recomendable - si usted está evitando la portabilidad de todos modos, sólo tiene que utilizar [[en primer lugar que tiene una comprensión mucho más matizada de tokenización, la división de palabras, etc ...
Chris Down

Respuestas:

28

[[ $a == $b ]]no es comparación, es coincidencia de patrones. Necesita [[ $a == "$b" ]]una comparación de igualdad byte a byte. =es lo mismo que ==en cualquier shell que admita [[...]](introducido por ksh).

[[...]]No es la shsintaxis estándar . El [ comando es estándar y el operador de comparación estándar que existe =(aunque algunas [implementaciones también lo reconocen ==).

Al igual que en cualquier argumento de cualquier comando, las variables deben ser citadas, entonces:

[ "$a" = "$b" ]

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

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

Para completar, otros operadores similares a la igualdad 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, algunas permiten expresiones aritméticas arbitrarias, pero eso no es portátil. Portablemente, uno puede usar [ "$((a))" -eq "$((b))" ]para eso. Vea también [ "$((a == b))" -ne 0 ]cuál sería el equivalente estándar (excepto que POSIXly, el comportamiento solo se especifica si $ay $bcontiene constantes enteras) de:
  • ((a == b)), desde ksh y también encontrado en zshy bash, devuelve verdadero si la evaluación de la expresión aritmética almacenada $aproduce el mismo número que el de $b. Por lo general, eso se usa para comparar números. Tenga en cuenta que existen variaciones entre los shells en cuanto a cómo se evalúan las expresiones aritméticas y qué números son compatibles (por ejemplo, bash y algunas implementaciones / versiones de ksh no admiten coma flotante o tratan los números con ceros iniciales como octales).

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

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

Ver también:

Stéphane Chazelas
fuente
13

Estos son equivalentes en bash:

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

Las dos primeras variables $ x no tienen que ser citadas. Bash realiza la división de palabras y la expansión del nombre de ruta 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én BashFAQ / 031: ¿Cuál es la diferencia entre test, [y [[? .

Lri
fuente