Comparación de enteros: expresión aritmética o expresión condicional

20

En Bash, se pueden comparar dos enteros usando una expresión condicional

arg1 OP arg2

OP es uno de -eq, -ne, -lt, -le, -gt, o -ge. Estos operadores binarios aritméticos devuelven verdadero si arg1 es igual a, no igual a, menor que, menor o igual que, mayor que, o mayor o igual que arg2 , respectivamente. Arg1 y arg2 pueden ser enteros positivos o negativos.

o expresión aritmética:

<= >= < > comparación

== != igualdad y desigualdad

¿Por qué tenemos dos formas diferentes de comparar dos enteros? ¿Cuándo usar cuál?

Por ejemplo, [[ 3 -lt 2 ]]usa expresión condicional y (( 3 < 2 ))usa expresión aritmética. Ambos devuelven 0 cuando la comparación es verdadera

Al comparar dos enteros, ¿pueden estos dos métodos usarse siempre de manera intercambiable? En caso afirmativo, ¿por qué Bash tiene dos métodos en lugar de uno?

Tim
fuente
1
= != < <= > >=comparar cadenas . 1 -eq 01but 1 != 01and 8 -lt 42but8 > 42
dave_thompson_085
Están sobrecargados en expresiones aritméticas.
Tim
1
Tendrá que buscar en los registros de cambios de bash para saber cuándo se agregó cada función. Sospecho que las expresiones aritméticas se agregaron mucho más tarde que el comando de prueba.
Glenn Jackman
No estoy preguntando sobre comparar cadenas. @muru.
Tim

Respuestas:

28

Sí, tenemos dos formas diferentes de comparar dos enteros.

Parece que estos hechos no son ampliamente aceptados en este foro:

  1. Dentro de la expresión idiomática [ ]los operadores de comparación aritmética son -eq, -ne, -lt, -le, -gty -ge.

    Como también están dentro de un comando de prueba y dentro de a [[ ]].

    Si dentro de este modismos, =, <, etc, son operadores de cadena.

  2. Dentro de la expresión idiomática (( ))los operadores de comparación aritmética son ==, !=, <, <=, >, y >=.

    No, esta no es una "expansión aritmética" (que comienza con a $) como $(( )). Se define como un "Comando Compuesto" en man bash.

    Sí, sigue las mismas reglas (internamente) de la "expansión aritmética" pero no tiene salida, solo un valor de salida. Se podría usar así:

if (( 2 > 1 )); then ...

¿Por qué tenemos dos formas diferentes de comparar dos enteros?

Supongo que este último (( ))fue desarrollado como una forma más simple de realizar pruebas aritméticas. Es casi lo mismo que el $(( ))pero simplemente no tiene salida.

¿Por qué dos? Pues lo mismo que por qué tenemos dos printf(externa e incorporado) o cuatro pruebas (externo test, incorporado test, [y [[). Así es como crecen las conchas, mejorando un área en un año, mejorando otra en el próximo año.

¿Cuándo usar cuál?

Esa es una pregunta muy difícil porque no debería haber una diferencia efectiva. Por supuesto, hay algunas diferencias en la forma en que un [ ]trabajo y un (( ))trabajo internamente, pero: ¿cuál es mejor comparar dos enteros? Cualquiera!

Al comparar dos enteros, ¿pueden estos dos métodos usarse siempre de manera intercambiable?

Por dos números me veo obligado a decir que sí.
Pero para las variables, expansiones, operaciones matemáticas puede haber diferencias clave que deberían favorecer a uno u otro. No puedo decir que absolutamente ambos son iguales. Por un lado, el (( ))podría realizar varias operaciones matemáticas en secuencia:

if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi

En caso afirmativo, ¿por qué Bash tiene dos métodos en lugar de uno?

Si ambos son útiles, ¿por qué no?

Yurij Goncharuk
fuente
1
=es una tarea y ==es una comparación en expansiones aritméticas. La pregunta lo cita correctamente. Pero la respuesta es incorrecta.
ceving
12

Históricamente, el testcomando existió primero (al menos desde la Séptima Edición de Unix en 1979). Se utiliza los operadores =y !=para comparar cadenas, y -eq, -ne, -lt, etc, para comparar números. Por ejemplo, test 0 = 00es falso, pero test 0 -eq 00es cierto. No sé por qué se eligió esta sintaxis, pero puede haber sido para evitar usar <y >, que el shell habría analizado como operadores de redirección. El testcomando obtuvo otra sintaxis unos años más tarde: [ … ]es equivalente a test ….

La [[ … ]]sintaxis condicional, en cuyo interior <y >se puede utilizar como operadores sin citar, se añadió más tarde, en ksh. Mantuvo la compatibilidad con versiones anteriores [ … ], por lo que utilizó los mismos operadores, pero agregó <y >para comparar cadenas (por ejemplo, [[ 9 > 10 ]]pero [[ 9 -lt 10 ]]). Para obtener más información, consulte el uso de soporte simple o doble - bash

Las expresiones aritméticas también llegaron después del testcomando, en el shell Korn , en algún momento de la década de 1980. Siguieron la sintaxis del lenguaje C, que era muy popular en los círculos de Unix. Por lo tanto, utilizaron operadores de C: ==para igualdad, <=para menor o igual, etc.

La Séptima Edición de Unix no tenía expresiones aritméticas, pero tenía el exprcomando , que también implementó una sintaxis tipo C para operaciones de enteros, incluidos sus operadores de comparación. En un script de shell, los caracteres <y >tuvieron que ser citados para protegerlos del shell, por ejemplo, if expr 1 \< 2; …es equivalente a if test 1 -lt 2; …. La adición de expresiones aritméticas al shell hizo que la mayoría de los usos de exprobsoletos, por lo que hoy en día no se conoce bien.

En un script sh, generalmente usaría expresiones aritméticas para calcular un valor entero y [ … ]comparar enteros.

if [ "$((x + y))" -lt "$z" ]; then 

En un script ksh, bash o zsh, puede usar ((…))para ambos.

if ((x + y < z)); then 

El [[ … ]]formulario es útil si desea utilizar condicionales que involucren otras cosas que no sean enteros.

Gilles 'SO- deja de ser malvado'
fuente
1

De acuerdo con la página de manual de prueba, = y! = Se usan para comparaciones de cadenas, mientras que las expresiones -eq, -gt, -lt, -ge, -le y -ne son comparaciones enteras. Siempre he seguido esta convención al escribir scripts de shell y siempre funciona. Tenga en cuenta que si tiene variables en la expresión, es posible que necesite citar las variables de alguna manera para evitar hacer una comparación nula.

En el papel, hacemos comparaciones de cadenas / números sin pensarlo mucho. Una computadora, por otro lado, no sabe si 987 es un número o una cadena de caracteres. Necesita que los diferentes operadores le digan a la computadora qué hacer para obtener el resultado correcto. Hay algo de información adicional aquí que explica algo de la historia. Esencialmente, las variables no están tipificadas y se han mantenido así por compatibilidad histórica.

señal7
fuente
En mi publicación, = y !=son operadores aritméticos, mientras que la página de manual de testsolo muestra operadores de expresión condicional.
Tim