Comparando números inteiros: expressão aritmética ou expressão condicional


20

No Bash, dois números inteiros podem ser comparados usando expressão condicional

arg1 OP arg2

OP é um dos -eq, -ne, -lt, -le, -gt, ou -ge. Esses operadores binários aritméticos retornam true se arg1 for igual a, diferente de, menor que, menor que ou igual a, maior que ou maior que ou igual a arg2 , respectivamente. Arg1 e arg2 podem ser inteiros positivos ou negativos.

ou expressão aritmética:

<= >= < > comparação

== != igualdade e desigualdade

Por que temos duas maneiras diferentes de comparar dois números inteiros? Quando usar qual?

Por exemplo, [[ 3 -lt 2 ]]usa expressão condicional e (( 3 < 2 ))expressão aritmética. Ambos retornam 0 quando a comparação é verdadeira

Ao comparar dois números inteiros, esses dois métodos sempre podem ser usados ​​de forma intercambiável? Se sim, por que o Bash tem dois métodos em vez de um?


11
= != < <= > >=comparar cadeias . 1 -eq 01mas 1 != 01e 8 -lt 42mas8 > 42
— dave_thompson_085

Eles estão sobrecarregados em expressões aritméticas.
— Tim

11
você precisará pesquisar nos registros de alterações do bash para descobrir quando cada recurso foi adicionado. Eu suspeito que as expressões aritméticas foram adicionadas muito mais tarde que o comando test.
— Glenn Jackman

Não estou perguntando sobre a comparação de strings. @muru.
— Tim

Respostas:


28

Sim, temos duas maneiras diferentes de comparar dois números inteiros.

Parece que esses fatos não são amplamente aceitos neste fórum:

  1. Dentro da linguagem [ ]dos operadores de comparação aritmética são -eq, -ne, -lt, -le, -gte -ge.

    Como eles também estão dentro de um comando de teste e dentro de um [[ ]].

    Sim dentro deste expressões idiomáticas, =, <, etc, são operadores de string.

  2. Dentro da linguagem (( ))dos operadores de comparação aritmética são ==, !=, <, <=, >, e >=.

    Não, essa não é uma "expansão aritmética" (que começa com a $) como $(( )). É definido como um "Comando composto" no man bash.

    Sim, segue as mesmas regras (internamente) da "expansão aritmética", mas não tem saída, apenas um valor de saída. Pode ser usado assim:

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

Por que temos duas maneiras diferentes de comparar dois números inteiros?

Eu acho que o último (( ))foi desenvolvido como uma maneira mais simples de realizar testes aritméticos. É quase o mesmo que o, $(( ))mas simplesmente não tem saída.

Por que dois? Bem, a mesma que por isso que temos dois printf(externa e builtin) ou quatro teste (externo test, builtin test, [e [[). É assim que as conchas crescem, melhorando alguma área em um ano, melhorando outras no próximo ano.

Quando usar qual?

Essa é uma pergunta muito difícil, porque não deve haver diferença efetiva. Claro que existem algumas diferenças na maneira como um [ ]trabalho e um (( ))trabalho internamente, mas: qual é o melhor para comparar dois números inteiros? Qualquer um!.

Ao comparar dois números inteiros, esses dois métodos sempre podem ser usados ​​de forma intercambiável?

Por dois números, sou obrigado a dizer que sim.
Mas para variáveis, expansões, operações matemáticas, pode haver diferenças importantes que devem favorecer uma ou outra. Não posso dizer que absolutamente ambos sejam iguais. Por um lado, o (( ))poderia executar várias operações matemáticas em sequência:

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

Se sim, por que o Bash tem dois métodos em vez de um?

Se ambos são úteis, por que não?


11
=é uma tarefa e ==é uma comparação em expansões aritméticas. A pergunta cita corretamente. Mas a resposta está errada.
— ceving 16/08/19

12

Historicamente, o testcomando existia primeiro (pelo menos desde a Unix Seventh Edition em 1979). Usou-se os operadores =e !=para comparar cadeias, e -eq, -ne, -lt, etc, para comparar os números. Por exemplo, test 0 = 00é falso, mas test 0 -eq 00é verdadeiro. Não sei por que essa sintaxe foi escolhida, mas pode ter sido para evitar o uso <e >, que o shell teria analisado como operadores de redirecionamento. O testcomando obteve outra sintaxe alguns anos depois: [ … ]é equivalente a test ….

A [[ … ]]sintaxe condicional, dentro da qual <e >pode ser usada como operadores sem citar, foi adicionada posteriormente, no ksh. Ele manteve a compatibilidade com versões anteriores e [ … ], portanto, usou os mesmos operadores, mas adicionou <e >comparou seqüências de caracteres (por exemplo, [[ 9 > 10 ]]mas [[ 9 -lt 10 ]]). Para obter mais informações, consulte Uso de colchetes simples ou duplos - bash

As expressões aritméticas também vieram depois do testcomando, no shell Korn , em algum momento da década de 1980. Eles seguiram a sintaxe da linguagem C, que era muito popular nos círculos Unix. Assim, eles usaram operadores de C: ==para igualdade, <=para menor ou igual, etc.

O Unix Seventh Edition não tinha expressões aritméticas, mas possuía o exprcomando , que também implementava uma sintaxe do tipo C para operações inteiras, incluindo seus operadores de comparação. Em um script de shell, os caracteres <e >tiveram que ser citados para protegê-los do shell, por exemplo, if expr 1 \< 2; …é equivalente a if test 1 -lt 2; …. A adição de expressões aritméticas ao shell fez com que a maioria dos usos exprfosse obsoleta, por isso não é bem conhecido hoje.

Em um script sh, você geralmente usaria expressões aritméticas para calcular um valor inteiro e [ … ]comparar números inteiros.

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

Em um script ksh, bash ou zsh, você pode usar ((…))para ambos.

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

O [[ … ]]formulário é útil se você deseja usar condicionais envolvendo outras coisas além de números inteiros.


1

De acordo com a página do manual de teste, = e! = São usados ​​para comparações de cadeias, enquanto as expressões -eq, -gt, -lt, -ge, -le e -ne são comparações inteiras. Eu sempre segui essa convenção ao escrever scripts de shell e sempre funciona. Esteja ciente de que se você tiver variáveis ​​na expressão, pode ser necessário citar as variáveis ​​de alguma forma para evitar uma comparação nula.

No papel, fazemos comparações de string / número sem muita reflexão. Um computador, por outro lado, não sabe se 987 é um número ou uma sequência de caracteres. Você precisa dos diferentes operadores para informar ao computador o que fazer para obter o resultado certo. Há algumas informações adicionais aqui que explicam parte da história. Essencialmente, as variáveis ​​não são tipadas e permaneceram assim para compatibilidade histórica.


No meu post, = e !=são operadores aritméticos, enquanto a página de manual testmostra apenas operadores de expressão condicional.
— Tim
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.