2

I have a case like this:

string1="some_string"
string2="some_string"
int1="0.87"
int2="${var}"

$var is the output of some other script, and it has the form 0.994343123 or 0.3454657 or whatever (starts with 0. and the biggest value is around 0.9972343)

Now, I don't know how bash works, but usually string 0.87 is never less than or equal to 0.9999999, they are just different.

I would need something like this (pseudocode):

if (string1 equals string2 and int1 is less than int2):
    do something;
else
    do something else.

What i would expect is 0.87687 is greater than 0.87 (correct?? i was never good at math...)

Can anyone help me with the code for that if??

Thanks in advance!

David Botezatu
  • 159
  • 2
  • 3
  • 11

3 Answers3

6

Since bash does not handle floating point arithmetic, you may use bc -l to compare 2 floating point numbers and join the condition with && as:

if [[ $string1 = $string2 && $(bc -l <<< "$int1 < $int2") -eq 1 ]]; then
   echo "yes"
else
   echo "no"
fi
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Can you please explain what `$(bc -l <<< "$int1 < $int2") -eq 1` means? And also why you put [[ ]] instead of just [ ]? Thanks! – David Botezatu Nov 16 '17 at 14:53
  • 1
    If you are using `bash` then prefer `[[ ... ]]` instead of old `[ ... ]` because `[` runs a separate process but `[[ ... ]]` is bash internal construct. `bc -l <<< "$int1 < $int2"` runs math expression `"$int1 < $int2"` using `bc -l` command where `-l` is for handling floating point numbers. – anubhava Nov 16 '17 at 14:56
  • 2
    Essentially `<<<` is the *herestring* construct. (related to *heredoc*) and it is only available in bash. It provides the equivalent of `echo "$int1 < $int2" | bc -l` without requiring the additional subshell for the pipe. – David C. Rankin Nov 16 '17 at 15:00
  • And what does `-eq 1` means? – David Botezatu Nov 16 '17 at 15:04
  • 2
    It is the math equivalent *equal to* operator. For a comparison, `bc` returns either `1` (true) or `0` (false) so `$(bc -l <<< "$int1 < $int2") -eq 1` tests whether the result of `$(bc -l <<< "$int1 < $in2")` is (true). – David C. Rankin Nov 16 '17 at 15:11
  • Ohh, now i get it. Thanks for help, @David C. Rankin and anubhava So here it goes, my 5th day of heavy use of bash passed :)) Still sooo much to learn – David Botezatu Nov 16 '17 at 15:16
  • 2
    Learning all of bash (and the nuances of shell scripting) is kind of like "getting to the end of the internet". The more you learn, the more you learn you have to learn... If you are doing anything Linux (or Unix or mac) then learning bash (the difference between it and POSIX shells, like Bourne shell, ash, and dash) as well as the utilities (`find, grep, sed, awk`, etc...) is time well spent. Good luck on day 6. – David C. Rankin Nov 16 '17 at 15:20
2

If the values are between 0 and 1, string comparison will work

s1=..; s2=..
v1="0.876"; v2="0.87"
[[ $s1 = $s2 && $v1 > $v2 ]] && echo yes || echo no 
karakfa
  • 66,216
  • 7
  • 41
  • 56
  • Chuckling, but yes, a lexigraphic sort works too. (and not just for values between 0 and 1) – David C. Rankin Nov 16 '17 at 15:09
  • Doesn't work... somehow messes with the rest of my script, and outputs everything as Failed instead of Passed. – David Botezatu Nov 16 '17 at 15:09
  • I'm sure there are some limitations, but understand the `>` is a bash *string comparison* operator where "*True if string1 sorts after string2 lexicographically.*". Essentially testing that `876` sorts after `87` (which it does) Like `abc` sorts after `ab`. – David C. Rankin Nov 16 '17 at 15:15
  • equivalent only the numbers are normalized (left zero padded for integers for example) or here as all are less than one. In general it doesn't work since "11' < "2" – karakfa Nov 16 '17 at 15:38
0
a=0.86
b=0.865
if ((`echo $a '<' $b|bc`)); then echo 'a<b'; fi

(You can replace the last line by

if (($(echo $a '<' $b|bc))); then echo 'a<b'; fi

but imho it is less readable)

user31264
  • 6,557
  • 3
  • 26
  • 40