No Bash, dois inteiros podem ser comparados usando expressão condicional
arg1 OP arg2
OP é um de
-eq
,-ne
,-lt
,-le
,-gt
, ou-ge
. Esses operadores binários aritméticos retornam verdadeiro se arg1 for igual a, não igual a, menor que, menor ou igual a, maior que ou maior 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 inteiros? Quando usar qual?
Por exemplo, [[ 3 -lt 2 ]]
usa expressão condicional e (( 3 < 2 ))
usa expressão aritmética. Ambos retornam 0 quando a comparação é verdadeira
Ao comparar dois inteiros, esses dois métodos sempre podem ser usados alternadamente? Se sim, por que o Bash tem dois métodos em vez de um?
Comentários
Resposta
Sim, temos duas maneiras diferentes de comparar dois números inteiros.
Parece que esses fatos não são amplamente aceitos neste fórum:
-
Dentro do idioma
[ ]
, os operadores para comparação aritmética são-eq
,-ne
,-lt
,-le
,-gt
e-ge
.Como eles também estão dentro de um comando de teste e dentro de um
[[ ]]
.Sim dentro deste idioma,
=
,<
, etc. são operadores de string. -
Dentro do idioma
(( ))
, os operadores para comparação aritmética são==
,!=
,<
,<=
,>
e>=
.Não, isso não é um “Aritmo expansão ética “(que começa com
$
) 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. Ele poderia ser usado assim:
if (( 2 > 1 )); then ...
Por que temos duas maneiras diferentes de comparar dois números inteiros?
Acho que o último (( ))
foi desenvolvido como uma maneira mais simples de realizar testes aritméticos. É quase o mesmo que $(( ))
, mas não tem saída.
Por que dois? Bem, o mesmo que porque temos dois printf
(externos e internos) ou quatro testes (externos test
, internos test
, [
e [[
). É assim que as cascas crescem, melhorando alguma área em um ano, melhorando outra 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 [ ]
funciona e um (( ))
funciona internamente, mas: qual é melhor comparar dois inteiros? Qualquer um !.
Ao comparar dois inteiros, esses dois métodos podem ser sempre usados de forma intercambiável?
Para dois números, sou obrigado a dizer sim.
Mas, para variáveis, expansões , operações matemáticas, pode haver diferenças importantes que devem favorecer um ou outro. Não posso dizer que absolutamente ambos são iguais. Por um lado, o (( ))
poderia realizar 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 ?.
Comentários
-
=
é uma atribuição e==
é uma comparação em expansões aritméticas. A pergunta o cita corretamente. Mas a resposta está errada. - Além disso,
(
não é uma palavra reservada em bash, portanto, não há necessidade de colocar espaços em torno de((
, como oposto a[
ou[[
Resposta
Historicamente, o comando test
existia primeiro (pelo menos desde a Sétima edição do Unix em 1979). Ele usou os operadores =
e !=
para comparar strings e -eq
, -ne
, -lt
, etc. para comparar 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 de <
e >
, que o shell teria analisados como operadores de redirecionamento. O comando test
obteve outra sintaxe alguns anos depois: [ … ]
é equivalente a test …
.
A [[ … ]]
sintaxe condicional, dentro da qual <
e >
podem ser usados como operadores sem aspas, foi adicionado posteriormente, em ksh. Manteve compatibilidade com versões anteriores de [ … ]
, então usou os mesmos operadores, mas adicionou <
e >
para comparar strings (por exemplo, [[ 9 > 10 ]]
mas [[ 9 -lt 10 ]]
). Para obter mais informações, consulte usando colchetes simples ou duplos – bash
Expressões aritméticas também vieram depois de test
comando,
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 C “s:==
para igualdade,<=
para menos ou igual, etc.
Sétima Edição do Unix não tinha expressões aritméticas, mas tinha o expr
comando , que também implementou um Sintaxe semelhante a C para operações inteiras, incluindo seus operadores de comparação. Em um script de shell, os caracteres <
e >
devem 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 tornou a maioria dos usos de expr
obsoleto, portanto não é “muito conhecido hoje.
Em um script sh, você” d geralmente usa expressões aritméticas para calcular um valor inteiro e [ … ]
para comparar inteiros.
if [ "$((x + y))" -lt "$z" ]; then …
Em um ksh , script bash ou zsh, você pode usar ((…))
para ambos.
if ((x + y < z)); then …
O [[ … ]]
o formulário é útil se você deseja usar condicionais envolvendo coisas que não sejam inteiros.
Resposta
De acordo com a página do manual de teste, = e! = são usados para comparações de strings, enquanto as expressões -eq, -gt, -lt, -ge, -le e -ne são comparações de inteiros. Sempre segui essa convenção ao escrever scripts de shell e ela sempre funciona. Esteja ciente de que, se houver 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 string / número sem pensar muito. Um computador, por outro lado, não sabe se 987 é um número ou uma string de caracteres. Você precisa que os diferentes operadores digam ao computador o que fazer para obter o resultado correto. Há algumas informações adicionais aqui que explicam um pouco da história. Essencialmente, as variáveis não foram digitadas e permaneceram assim para compatibilidade histórica.
Comentários
- Em minha postagem,
=
e!=
são operadores aritméticos, enquanto a página de manual detest
mostra apenas operadores de expressão condicional.
= != < <= > >=
comparar strings .1 -eq 01
, mas1 != 01
e8 -lt 42
, mas8 > 42