Comparação de números decimais no bash

Comparação de números decimais no bash

Minha pesquisa esta manhã foi sobre como comparar dois números decimais no bash, e cheguei a esta resposta:Como comparar com o número de ponto flutuante em um script de shell. Este, no entanto, não incluiessa resposta aqui:

$ [[ ((3.56 < 2.90)) ]]; echo $?
1
$ [[ ((3.56 < 4.90)) ]]; echo $?
0

Considerando que a resposta foi rejeitada e parece algum tipo de bashismo incomum, esta avaliação aritmética é confiável quanto à precisão?

Responder1

bashnão entende números de ponto flutuante.
Citando bashpágina de manual, seçãoAVALIAÇÃO ARITMÉTICA:

A avaliação é feita em números inteiros de largura fixa […].

Então ((3 < 4))ou ((3 < 2))são na verdade expressões aritméticas corretas. Você pode digitar o seguinte:

$ echo "$((3 < 4)) -- $((3 < 2))"

saída:1 -- 0

Mas $ echo $((3.3 < 3.6))retornará uma mensagem de erro de sintaxe. No seu exemplo, você está comparando strings. Daí alguns exemplos:

$ [[ ((3.56 < 04.90)) ]]; echo $?

saída:1

Responder2

Dentro [[...]] <é para comparação de strings.

Então [[ 3.56 < 2.90 ]]or [[ (3.56 < 2.90) ]]or [[ ((3.56 < 2.90)) ]]or [[ (((3.56 < 2.90))) ]]... está apenas comparando a 3.56string com a 2.90string lexicamente (e lexicamente, 3é maior que, 10por exemplo).

Para comparação de números inteiros, é [[ 3 -lt 2 ]]ou (( 3 < 2 )). Se você deseja uma comparação de ponto flutuante, você precisa ksh93, zshou yashou de um utilitário externo como awkou perl; bashnão posso fazer isso.

Você poderia, por exemplo, definir uma função como:

compare() (IFS=" "
  exec awk "BEGIN{if (!($*)) exit(1)}"
)

Que você pode usar, por exemplo, como:

if compare '1.5*10 < 1e3'; then
  echo less
fi

Ou mesmo para isso importa:

if compare '"bar" < "foo"'...

para fazer comparações de strings.

Não passe dados não controlados fornecidos externamente para essa comparefunção, pois isso constituiria uma vulnerabilidade de injeção de comando (os dados são interpretados como awkcódigo, awkpodem executar comandos com seus, system()por exemplo).

informação relacionada