¿Alguien puede explicar la diferencia entre -eq
y ==
en las secuencias de comandos bash?
¿Hay alguna diferencia entre lo siguiente?
[ $a -eq $b ]
y [ $a == $b ]
¿Es simplemente que ==
solo se usa cuando las variables contienen números?
¿Alguien puede explicar la diferencia entre -eq
y ==
en las secuencias de comandos bash?
¿Hay alguna diferencia entre lo siguiente?
[ $a -eq $b ]
y [ $a == $b ]
¿Es simplemente que ==
solo se usa cuando las variables contienen números?
Respuestas:
Es al revés: =
y ==
son para comparaciones de cadenas, -eq
es para las numéricas. -eq
está en la misma familia que -lt
, -le
, -gt
, -ge
, y -ne
, si eso ayuda a recordar cuál es cuál.
==
es un bash-ism, por cierto. Es mejor usar POSIX =
. En bash, los dos son equivalentes, y en sh simple =
es el único garantizado para funcionar.
$ a=foo
$ [ "$a" = foo ]; echo "$?" # POSIX sh
0
$ [ "$a" == foo ]; echo "$?" # bash specific
0
$ [ "$a" -eq foo ]; echo "$?" # wrong
-bash: [: foo: integer expression expected
2
(Nota al margen: ¡Cite esas expansiones variables! No omita las comillas dobles anteriores).
Si está escribiendo una #!/bin/bash
secuencia de comandos, le recomiendo usar en su [[
lugar . La forma duplicada tiene más características, más sintaxis natural y menos problemas que lo harán tropezar. Ya no se requieren comillas dobles $a
, por ejemplo:
$ [[ $a == foo ]]; echo "$?" # bash specific
0
Ver también:
[[ $var = $pattern ]]
, si desea que lo que de otro modo se interpretaría como un patrón fnmatch se interprete como una cadena literal. La cadena foo
no tiene interpretación no literal, lo que hace que dejar las comillas sea completamente seguro; es solo si el OP quería coincidir, digamos, foo*
(con el asterisco como literal, no significando nada que pueda venir después de la cadena foo
) que se necesitarían comillas o escape.
[[
citadas dentro de ser un bashism (lo que indica que esa fue la única razón por la que no estaba dando la respuesta a +1).
[ ... ]
y doble signo igual ==
. : - /
Depende de la construcción de prueba alrededor del operador. Sus opciones son paréntesis dobles, llaves dobles, llaves simples o prueba
Si usa ((...)) , está probando la equidad aritmética con ==
como en C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Nota: 0
significa true
en el sentido de Unix y no cero es una prueba fallida)
Usar -eq
dentro del paréntesis doble es un error de sintaxis.
Si estas usando [...] (o llave simple) o [...] (o llave doble), o test
puede usar uno de -eq, -ne, -lt, -le, -gt, o -ge como una comparación aritmética .
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
El ==
interior de llaves simples o dobles (o test
comando) es uno de los operadores de comparación de cadenas :
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
Como operador de cadena, =
es equivalente ==
y nota el espacio en blanco alrededor =
o ==
es necesario.
Si bien puede hacer [[ 1 == 1 ]]
o [[ $(( 1+1 )) == 2 ]]
está probando la igualdad de la cadena, no la igualdad aritmética.
Entonces -eq
el resultado probablemente se esperaba que el valor entero de 1+1
sea igual a 2
pesar de que RH es una cadena y tiene un espacio final:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
Mientras que una comparación de cadenas de la misma recoge el espacio final y, por lo tanto, la comparación de cadenas falla:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
Y una comparación de cadenas errónea puede producir la respuesta incorrecta completa. '10' es lexicográficamente menor que '2', por lo que una comparación de cadenas devuelve true
o 0
. Muchos son mordidos por este error:
$ [[ 10 < 2 ]]; echo $?
0
vs la prueba correcta para ser 10 aritméticamente menor que 2:
$ [[ 10 -lt 2 ]]; echo $?
1
En los comentarios, hay una cuestión de razón técnica que usa el entero -eq
en cadenas devuelve True para cadenas que no son lo mismo:
$ [[ "yes" -eq "no" ]]; echo $?
0
La razón es que Bash no está tipificado . los-eq
hace que las cadenas se interpreten como enteros si es posible, incluida la conversión de base:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
Y 0
si Bash piensa que es solo una cadena:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
Entonces [[ "yes" -eq "no" ]]
es equivalente a[[ 0 -eq 0 ]]
Última nota: muchas de las extensiones específicas de Bash para las construcciones de prueba no son POSIX y, por lo tanto, fallarán en otros shells. Otros proyectiles generalmente no son compatibles [[...]]
y ((...))
o==
.
[[ "yes" -eq "no" ]]
devolver True. ¿Cómo bash coacciona estas cadenas a valores enteros que se pueden comparar? ;-)
[[ "yes" -eq "no" ]]
es equivalente a [[ "yes" -eq 0 ]]
o [[ "yes" -eq "any_noninteger_string" ]]
: todo es verdadero. La -eq
comparación de enteros de fuerzas. El "yes"
se interpreta como un entero 0
; la comparación es Verdadera si el otro entero es 0
o el resultado de la cadena es 0
.
==
en los ejemplos de código y solo menciona (portátil, estandarizado) =
debajo.
==
es un alias específico de bash para =
y realiza una comparación de cadena (léxica) en lugar de una comparación numérica. eq
siendo una comparación numérica, por supuesto.
Finalmente, generalmente prefiero usar el formulario if [ "$a" == "$b" ]
==
aquí es una mala forma, ya que solo =
POSIX lo especifica.
==
, póngalo entre [[
y ]]
. (Y asegúrese de que la primera línea de su script especifique el uso /bin/bash
).
Chicos: Varias respuestas muestran ejemplos peligrosos. El ejemplo de OP [ $a == $b ]
utilizó específicamente la sustitución de variables sin comillas (a partir de la edición de octubre '17). Para [...]
eso es seguro para la igualdad de cadena.
Pero si va a enumerar alternativas como [[...]]
, debe informar también que se debe citar el lado derecho. Si no se cita, ¡es una coincidencia de patrón! (De la página de manual de bash: "Cualquier parte del patrón puede ser citada para forzar que coincida como una cadena").
Aquí en bash, las dos declaraciones que arrojan "sí" son coincidencia de patrones, otras tres son igualdad de cadena:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
[ "$lht" = "$rht" ]
entre comillas para ser confiable incluso para la igualdad. Si tiene un archivo creado con touch 'Afoo -o AB'
, [ $lft = $rht ]
devolverá verdadero, a pesar de que ese nombre de archivo no es idéntico en absolutoAB
.
[[
en su conjunto es un ksh-ism de la era de 1980 que bash (y muchos otros shells) adoptaron. Ese es el punto - si usted tiene[[
en absoluto , entonces se puede asumir con seguridad que todas las extensiones KSH implementados alrededor de él (fnmatch()
patrón al estilo de juego, las expresiones regulares con ERE=~
, y sí, la supresión de la cadena de la división y el englobamiento sistema de archivos) serán disponible. Dado que la[[
sintaxis no es POSIX en su totalidad, no hay pérdida de portabilidad adicional al suponer que las funciones con las que nació estarán disponibles.