Comparando números no Bash

Estou começando a aprender sobre como escrever scripts para o terminal bash, mas não consigo descobrir como fazer com que as comparações funcionem corretamente. O script que estou usando é:

echo "enter two numbers"; read ab; echo "a=$a"; echo "b=$b"; if [ $a \> $b ]; then echo "a is greater than b"; else echo "b is greater than a"; fi; 

O problema que tenho é que ele compara o número do primeiro dígito, isto é, 9 é maior que 10000, mas 1 é maior que 09

Como posso converter os números em um tipo para fazer uma comparação verdadeira?

   

No bash, você deve fazer o seu check-in no contexto aritmético :

 if (( a > b )); then ... fi 

Para shells POSIX que não suportam (()) , você pode usar -gt e -gt .

 if [ "$a" -gt "$b" ]; then ... fi 

Você pode obter uma lista completa de operadores de comparação com o help test .

Claro e simples

 #!/bin/bash a=2462620 b=2462620 if [ "$a" -eq "$b" ];then echo "They're equal"; fi 

Você pode conferir esta planilha de cheats se quiser mais comparsões numéricas no maravilhoso mundo do Bash Scripting.

Logo, inteiros só podem ser comparados com:

 -eq # equal -ne # not equal -lt # less than -le # less than or equal -gt # greater than -ge # greater than or equal 

Há também uma coisa legal que algumas pessoas podem não saber:

 echo $(( a < b ? a : b )) 

Este código irá imprimir o menor número de b

No Bash eu prefiro fazer isso, pois ele se endereça mais como uma operação condicional, ao contrário do uso de (( )) que é mais aritmético.

 [[ N -gt M ]] 

A menos que eu faça coisas complexas como

 (( (N + 1) > M )) 

Mas todo mundo só tem suas próprias preferências. O triste é que algumas pessoas impõem seus padrões não oficiais.

Atualizar:

Você também pode fazer isso:

 [[ 'N + 1' -gt M ]] 

Que permite adicionar algo mais que você poderia fazer com [[ ]] além de materiais aritméticos.

Esse código também pode comparar carros alegóricos. Ele está usando o awk (não é puro bash), no entanto, isso não deve ser um problema, já que o awk é um comando POSIX padrão que é mais provável que seja enviado por padrão com o seu sistema operacional.

 $ awk 'BEGIN {return_code=(-1.2345 == -1.2345) ? 0 : 1; exit} END {exit return_code}' $ echo $? 0 $ awk 'BEGIN {return_code=(-1.2345 >= -1.2345) ? 0 : 1; exit} END {exit return_code}' $ echo $? 0 $ awk 'BEGIN {return_code=(-1.2345 < -1.2345) ? 0 : 1; exit} END {exit return_code}' $ echo $? 1 $ awk 'BEGIN {return_code=(-1.2345 < 2) ? 0 : 1; exit} END {exit return_code}' $ echo $? 0 $ awk 'BEGIN {return_code=(-1.2345 > 2) ? 0 : 1; exit} END {exit return_code}' $ echo $? 

Para torná-lo mais curto para uso, use esta function:

 compare_nums() { # Function to compare two numbers (float or integers) by using awk. # The function will not print anything, but it will return 0 (if the comparison is true) or 1 # (if the comparison is false) exit codes, so it can be used directly in shell one liners. ############# ### Usage ### ### Note that you have to enclose the comparison operator in quotes. ############# # compare_nums 1 ">" 2 # returns false # compare_nums 1.23 "< =" 2 # returns true # compare_nums -1.238 "<=" -2 # returns false ############################################# num1=$1 op=$2 num2=$3 E_BADARGS=65 # Make sure that the provided numbers are actually numbers. if ! [[ $num1 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num1 is not a number"; return $E_BADARGS; fi if ! [[ $num2 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num2 is not a number"; return $E_BADARGS; fi # If you want to print the exit code as well (instead of only returning it), uncomment # the awk line below and comment the uncommented one which is two lines below. #awk 'BEGIN {print return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}' awk 'BEGIN {return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}' return_code=$? return $return_code } $ compare_nums -1.2345 ">=" -1.2345 && echo true || echo false true $ compare_nums -1.2345 ">=" 23 && echo true || echo false false 

Eu resolvi isso usando uma pequena function para converter strings de versão em valores inteiros simples que podem ser comparados:

 function versionToInt() { local IFS=. parts=($1) let val=1000000*parts[0]+1000*parts[1]+parts[2] echo $val } 

Isso faz duas suposições importantes:

  1. A input é uma ” cadeia semântica normal ”
  2. Cada parte está entre 0-999

Por exemplo

 versionToInt 12.34.56 # --> 12034056 versionToInt 1.2.3 # --> 1002003 

Exemplo de teste se o comando npm atende ao requisito mínimo …

 NPM_ACTUAL=$(versionToInt $(npm --version)) # Capture npm version NPM_REQUIRED=$(versionToInt 4.3.0) # Desired version if [ $NPM_ACTUAL \< $NPM_REQUIRED ]; then echo "Please update to npm@latest" exit 1 fi 

Se você tem carros alegóricos, você pode escrever uma function e usá-la, por exemplo

 #!/bin/bash function float_gt() { perl -e "{if($1>$2){print 1} else {print 0}}" } x=3.14 y=5.20 if [ $(float_gt $x $y) == 1 ] ; then echo "do stuff with x" else echo "do stuff with y" fi