Comparação de números decimais no bash

6

Minha pesquisa esta manhã foi sobre como eu poderia 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 inclui esta 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 para precisão?

    
por Teresa e Junior 14.06.2014 / 14:59

2 respostas

10

bash não entende números de ponto flutuante.
Citando a página de manual bash , seção AVALIAÇÃO ARITMÉTICA :

Evaluation is done in fixed-width integers […].

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

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

output: 1 -- 0

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

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

output: 1

    
por 14.06.2014 / 15:39
11

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

Portanto, [[ 3.56 < 2.90 ]] ou [[ (3.56 < 2.90) ]] ou [[ ((3.56 < 2.90)) ]] ou [[ (((3.56 < 2.90))) ]] ... está apenas comparando a string 3.56 com a string 2.90 lexicalmente (e lexicalmente, 3 é maior que 10 por exemplo).

Para comparação de números inteiros, é [[ 3 -lt 2 ]] ou (( 3 < 2 )) . Se você quiser uma comparação de ponto flutuante, precisará de ksh93 , zsh ou yash ou um utilitário externo como awk ou perl ; bash não pode fazer isso.

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

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

Que você poderia usar, por exemplo, como:

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

Ou até mesmo para isso:

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

para fazer comparações de strings.

Não passe dados não controlados fornecidos externamente para essa função compare , pois isso constituiria uma vulnerabilidade de injeção de comando (os dados são interpretados como awk code, awk pode executar comandos com seu system() , por exemplo).

    
por 14.06.2014 / 15:49