Verify amount in bash [duplicate] - bash

This question already has answers here:
How can I compare two floating point numbers in Bash?
(22 answers)
Closed 5 years ago.
Currently i'm writing a script that checks whether an amount is higher than the other.
if [ "324,53" -gt "325,00" ]; then
echo "Amount is higher!"
else
echo "Amount is lower."
fi
Obviously i'm receiving the error: "integer expression expected" when running this. I tried to use sed 's/[^0-9]*//g'` but i need the full number again for further use. Problem is that I don't know the correct way how to do this. Can anybody give some advice?

Bash can't handle floating point numbers. You need to use an external tool, e.g. bc, but you need to use decimal point, not comma:
if (( $(bc <<< '324.53 > 325.00') )) ; then
bc prints 1 when the condition is true, and 0 when it's false. $(...) takes the output of the command, and (( ... )) interpret it as a number, returning false for zero and true for anything else.

Related

Unix script error while assigning command substitution to array variable [duplicate]

This question already has answers here:
Why does my Bash code fail when I run it with 'sh'?
(2 answers)
Closed 2 years ago.
From the below script I am assigning the command substitution for the array variables.
When I execute the script, the script is throwing error as
myscript.sh: 22: scr4.sh: Syntax error: "(" unexpected
ie while executing the command suite=( echo $Suites ).
I took this script from Advanced Bash scripting Guide pdf.
When I run this command by command in CLI, there is no issue.
What is the solution for this?
#!/bin/bash
Suites="Clubs
Diamonds
Hearts
Spades"
Denominations="2
3
4
5
6
7
8
9
10
Jack
Queen
King
Ace"
suite=( `echo $Suites` )
denomination=( `echo $Denominations` )
num_suites=${#suite[*]}
num_denominations=${#denomination[*]}
echo -n "${denomination[$((RANDOM%num_denominations))]} of "
echo ${suite[$((RANDOM%num_suites))]}
exit 0
You're probably using the wrong interpreter.
$ bash cards.sh
King of Diamonds
$ sh cards.sh
cards.sh: 22: Syntax error: "(" unexpected
POSIX shell does not support arrays. You define an array on line 22 (suite=( `echo $Suites` )) and another on the next code line, then most of your remaining lines refer to those arrays. $RANDOM is also unavailable in POSIX.
Another note, you don't need those subshells. Here's a cleaned up version of your code:
#!/bin/bash
suit=( Clubs Diamonds Hearts Spades )
denomination=( {2..10} Jack Queen King Ace )
echo -n "${denomination[ $(( RANDOM % ${#denomination[#]} )) ]} of "
echo "${suit[ $(( RANDOM % ${#suit[#]} )) ]}"
exit 0
This doesn't launch any subshells. Instead, it's directly defining the arrays. I used {2..10} (another bashism) as shorthand for listing each number. Rather than storing the lengths in variables, I'm invoking them directly in the modulo math, which I've spaced out to make more legible.
I changed ${variable[*]} to ${variable[#]} as well. This doesn't matter in your particular code, but it's generally better to use # since it is better at preserving spacing.
I also corrected the spelling of your suite variable to suit. Feel free to revert if that's actually what you desired (perhaps due to a spoken language difference). It of course doesn't really matter as long as you're consistent; bash doesn't know English 😉

Bash float comparison error with different number of digits [duplicate]

This question already has answers here:
How can I compare two floating point numbers in Bash?
(22 answers)
Closed 4 years ago.
Ok, so I've been working around with some results from speedtest-cli and realised that I had some errors due to the fact that bash doesn't seem to correctly handle the change in digits?
Anyways, here is an example ran directly from the terminal :
ubuntu:~$ l1=9.99
ubuntu:~$ l2=10.44
ubuntu:~$ if [[ (($l2 > $l1)) ]]; then echo "Ok"; fi
ubuntu:~$ if [[ (($l2 < $l1)) ]]; then echo "Not ok"; fi
Not ok
Of course, comparing eg. 10.33 and 11.34 would give the right result.
How does this happen and how can I fix it? Is there another way to achieve this comparison?
Thanks
You're using string comparison, not numeric. Inside double square brackets, parentheses are used just for precedence, so your condition is equivalent to
[[ $l2 < $l1 ]]
To use numeric comparison, use double parentheses without the square ones:
(( l2 < l1 ))
Unfortunately, this wouldn't work either, as bash doesn't support floating point arithmetic, only integer.
You need to use an external tool, e.g.
bc <<< "$l1 < $l2"
bc returns 1 for true and 0 for false.

How to compare between two pings in shell script? [duplicate]

This question already has answers here:
Unable to compare ping times on fly
(3 answers)
How can I compare numbers in Bash?
(10 answers)
Closed 4 years ago.
I am trying to find out which search engine will give the fastest ping for me and then get the result in a single output but I am not able to figure out how to put if statement for that in shell script.
My code is below
png=10000
for item in ${array[*]}
do
png_cal=`ping -c 4 "$item" | tail -1| awk '{print $4}' | cut -d '/' -f 2`
if [[ $png < $png_cal ]];then
png=${png_cal}
link=${item}
fi
done
and my program is not going in the loop again after first loop.
Your immediate problem is how to compare floating point numbers in Bash, whereas your code would only compare integers.
I got it to work like this:
array=(www.google.com www.facebook.com www.linkedin.com www.stackoverflow.com)
fastest_response=2147483647 # largest possible integer
for site in ${array[*]}
do
this_response=`ping -c 4 "$site" | awk 'END { split($4,rt,"/") ; print rt[1] }'`
if (( $(bc -l <<< "$this_response < $fastest_response") )) ; then
fastest_response=$this_response
fastest_site=$site
fi
echo "Got $this_response for $site ; fastest so far $fastest_site"
done
echo $fastest_site
Further explanation:
See this related Stack Overflow answer for why the expression to compare floats in Bash is so complicated.
I simplified the calls to tail, awk etc by just doing all that in awk, which is cleaner.
Notice I gave the variables more meaningful names. It's so much easier to think about code when the variable names announce themselves precisely for what they really are.
Instead of 10,000 I chose to use the largest possible integer in Bash. It's just a style thing as it seemed less arbitrary than 10,000.
I also made the script communicate a bit with the user, because the user won't want to sit there waiting for pings without knowing what's going on.
And the winner is:
$ bash test.sh
Got 21.786 for www.google.com ; fastest so far www.google.com
Got 20.879 for www.facebook.com ; fastest so far www.facebook.com
Got 20.555 for www.linkedin.com ; fastest so far www.linkedin.com
Got 21.368 for www.stackoverflow.com ; fastest so far www.linkedin.com
www.linkedin.com

Comparisons in Shell [duplicate]

This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 4 years ago.
I am trying to write a program that checks whether the number stored in a file (variable n) + 8 is greater or equal to 100. If it is, terminate, else, add 8 and store back in file. However, when I try running it, it says the command in line 4 (if condition) cannot be found. Can someone please explain to me why this isn't working? Thanks.
#!/bin/bash
n=$(cat test.txt)
if [$(($n+8)) -ge 100]
then
echo 'terminated program' > test.txt
else
m=$(($n+3))
echo $m > test.txt
fi
You miss some spaces :
if [$(($n+8)) -ge 100]
->
if [ $(($n+8)) -ge 100 ]
But while using bash, prefer a modern solution, using bash arithmetic :
if (( n+8 >= 100 ))
or even
if ((n+8>=100))
Like #Gordon Davisson said in comments : arithmetic contexts like inside (( )) are one of the few places in bash where spaces aren't critical delimiters.

division in shell script [duplicate]

This question already has answers here:
floating point accuracy with bash
(2 answers)
Closed 6 years ago.
I am trying to do a simple division of variables in a shell script, but it is somehow not working. May be there I am overlooking something really basic. Below is a script for calculating total number of reads from a bam file for bams files read from a list file. I need to assign the output to a variable and calculate a ratio. This is what I have:
normNum=100000
while IFS=$'\t' read -r bamfile name; do
#for i in $(ls *.bam)
echo $bamfile
mappedReads="$(samtools idxstats $bamfile | awk '{s+=$3} END {print s}')"
echo $normNum
echo $mappedReads
#scalingFactor="$((normNum / mappedReads))"
#echo $scalingFactor
scalingFactor=`printf "%0.3f\n" $((normNum / mappedReads))`
echo $scalingFactor
done < "${file}_temp"
The different prints are giving my correct number except for scalingFactor, which gives me 0.
merged_DupRem.bam
100000
24226512
0.000
Any pointers please?
Thanks..
Bash does integer math, not floating point. You will need to use awk or bc to provide floating point output. e.g. with bc
scalingFactor=$(printf "scale=3; %d/%d\n" $normNum $mappedReads | bc)

Resources