27

Can you please suggest to me the syntax for doing floating point comparison in a Bash script? I would ideally like to use it as part of an if statement. Here is a small code snippet :

key1="12.3"
result="12.2"

if (( $result <= $key1 ))
then
    # some code here
fi
codeforester
  • 39,467
  • 16
  • 112
  • 140
Kiran
  • 8,034
  • 36
  • 110
  • 176
  • 2
    Sounds like it's time to write that script in a different shell scripting language. You might like Python. –  Mar 11 '10 at 12:22
  • 1
    @Roger: don't underestimate bash, it's often a lot more powerful than people think.. except for, you know, dealing with floats.. :) – falstro Mar 11 '10 at 12:23
  • Ya, Python is an option, my entire project is in shell script and would be difficult to export it to python.. Bash in itself is very flexible though.. I wish it had a good suppporting when handling integers and floating point numbers – Kiran Mar 11 '10 at 12:25
  • 1
    @kiran, some shell like ksh/zsh supports floating point. otherwise, the next best thing is awk. (for shell scripting, its a very powerful tool), so learn to make use of it. – ghostdog74 Mar 11 '10 at 12:31
  • 1
    @ghostdog: Not really how? Your accepted answer is all about using an additional language. –  Mar 11 '10 at 12:32
  • Thanks.. I need to.. I am not so well versed using awk still.. – Kiran Mar 11 '10 at 12:37
  • @roger, what i meant is, just because it can't do float comparison, doesn't mean straight away you write the script in another language. for all you know, that may be only OP's problem and he may have already written a bigger part of it in shell. I am not saying you can't use Python, though , but maybe `python -c` is more appropriate. – ghostdog74 Mar 11 '10 at 13:13

7 Answers7

65

bc is your friend:

key1="12.3"
result="12.2"
if [ $(bc <<< "$result <= $key1") -eq 1 ]
    then
    # some code here
fi

Note the somewhat obscure here string (<<<) notation, as a nice alternative to echo "$result <= $key1" | bc.

Also, the un-bash-like bc prints 1 for true and 0 for false.

Chen Levy
  • 15,438
  • 17
  • 74
  • 92
  • 1
    bc (or even dc) is good for this, and is certainly easier to read than the awk method, but doing it this way requires a subshell (or a pipe). In terms of efficiency expr is better and I find it easier to read, too. But still, +1 for bc! – sorpigal Mar 11 '10 at 12:35
  • if what you meant by "easier to read than awk" means its shorter, that's because I am separating shell variables against awk variables. I can also write it like `var=$(awk 'BEGIN{print "'$result'"<"'$key1'"?1:0}') ` – ghostdog74 Mar 11 '10 at 12:42
  • 1
    Even if you do that it's quite verbose. Quotes inside quotes and a ternary operator? I'm sure you see what I mean. – sorpigal Mar 11 '10 at 12:47
  • Just what the doctor ordered man!! This helped me solve a problem so thank you and +1 – Bitcoin Murderous Maniac Nov 05 '18 at 02:11
21

bash doesn't do floats, use awk

key1=12.3
result=12.5
var=$(awk 'BEGIN{ print "'$key1'"<"'$result'" }')    
# or var=$(awk -v key=$key1 -v result=$result 'BEGIN{print result<key?1:0}')
# or var=$(awk 'BEGIN{print "'$result'"<"'$key1'"?1:0}')
# or 
if [ "$var" -eq 1 ];then
  echo "do something"
else
  echo "result more than key"
fi

there are other shells that can do floats, like zsh or ksh, you might like to try using them as well

Henk Langeveld
  • 8,088
  • 1
  • 43
  • 57
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • Thanks GhostDog74, Your comments did help.. you have been a great support.. Thanks everyone – Kiran Mar 11 '10 at 12:28
  • 4
    This looks like a rather awkward way to do it (no pun intended). – sorpigal Mar 11 '10 at 12:37
  • 2
    I'm not 100% sure, but the double quotes in the awk expression result in awk acting weirdly, because, for example, `awk 'BEGIN{ print "3.05">="20"}` returns 1. After removing double quotes, it acts as expected. – zoldar Sep 23 '15 at 09:09
  • 2
    Didn't work for me until I used: `print (result < key)` – user1766555 Apr 30 '19 at 09:19
  • Works for me. I had to remove all quotes from $key < $result section. Otherwise it seemed to be doing lexicographic compae instead of numerical. Thanks! – LFMekz Jan 13 '21 at 05:00
  • And the awkward moment, you cannot use greater than symbol > – MaXi32 Aug 26 '21 at 05:50
  • I think the approach with exit in the answer (below?) by Steve Schnepp is slightly better. I'll update this answer above and remove most of the quotes. – hansfn Aug 11 '23 at 12:49
8

another simple clear way with bc is this:

if ((`bc <<< "10.21>12.22"`)); then echo "true"; else echo "false"; fi
Aquarius Power
  • 3,729
  • 5
  • 32
  • 67
6

Using the exit() function of awk makes it almost readable.

key1=12.3
result=12.5

# the ! awk is because the logic in boolean tests 
# is the opposite of the one in shell exit code tests
if ! awk "BEGIN{ exit ($result <= $key1) }"
then
        # some code here that is only executed if $result <= $key1
fi

Note that there is not need to reuse the [ operator as if already uses the exit value.

Steve Schnepp
  • 4,620
  • 5
  • 39
  • 54
  • Are you sure this is working, I did not get the correct output for this.. you might need to try this, please put the meaning of "some code here", does the result is true or what? You need to explain that. – MaXi32 Aug 26 '21 at 05:37
  • 1
    You are totally right, i tested it and it doesn't work. I don't know if it worked in the past, but I edited my answer to have a correct one. – Steve Schnepp Oct 19 '21 at 07:16
  • This was the best solution for my case since the others failed when comparing an integer (1) to an empty string. Thanks for this answer. – Kalle Jun 22 '22 at 07:18
0
### The funny thing about bash is this:
> AA=10.3
> BB=10.4
### It needs `$` for compare
> [[ $AA > $BB ]] && echo Hello
> [[ $AA < $BB ]] && echo Hello
Hello

Yeah, I know it's cheating but it works. And scientific notation does not work here.

G. Sliepen
  • 7,637
  • 1
  • 15
  • 31
linuxaos
  • 87
  • 1
0

yu can use this awk comparison inside a if clause, it will print 1 (true) if the condition is true else 0 (false), and those values will be interpreted as boolean vals by the if

if (( $(awk 'BEGIN {print ("'$result'" <= "'$key1'")}') )); then
    echo "true"
else
    echo "false"
fi
ungalcrys
  • 5,242
  • 2
  • 39
  • 23
0

I was using bc until now, I found in some distros there was not bc installed, and I did not want to go through sudo apt install bc but python was there. Using python:

  if python -c "import sys; sys.exit(0 if float($float_1) > float($float_2) else 1)"; 
    then
    echo "true"
         else
           echo "false"
  fi
Rakib Fiha
  • 473
  • 8
  • 13