Random number from a range in a Bash Script - bash

I need to generate a random port number between 2000-65000 from a shell script. The problem is $RANDOM is a 15-bit number, so I'm stuck!
PORT=$(($RANDOM%63000+2001)) would work nicely if it wasn't for the size limitation.
Does anyone have an example of how I can do this, maybe by extracting something from /dev/urandom and getting it within a range?

shuf -i 2000-65000 -n 1
Enjoy!
Edit: The range is inclusive.

On Mac OS X and FreeBSD you may also use jot:
jot -r 1 2000 65000

According to the bash man page, $RANDOM is distributed between 0 and 32767; that is, it is an unsigned 15-bit value. Assuming $RANDOM is uniformly distributed, you can create a uniformly-distributed unsigned 30-bit integer as follows:
$(((RANDOM<<15)|RANDOM))
Since your range is not a power of 2, a simple modulo operation will only almost give you a uniform distribution, but with a 30-bit input range and a less-than-16-bit output range, as you have in your case, this should really be close enough:
PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 ))

and here's one with Python
randport=$(python -S -c "import random; print random.randrange(2000,63000)")
and one with awk
awk 'BEGIN{srand();print int(rand()*(63000-2000))+2000 }'

The simplest general way that comes to mind is a perl one-liner:
perl -e 'print int(rand(65000-2000)) + 2000'
You could always just use two numbers:
PORT=$(($RANDOM + ($RANDOM % 2) * 32768))
You still have to clip to your range. It's not a general n-bit random number method, but it'll work for your case, and it's all inside bash.
If you want to be really cute and read from /dev/urandom, you could do this:
od -A n -N 2 -t u2 /dev/urandom
That'll read two bytes and print them as an unsigned int; you still have to do your clipping.

If you're not a bash expert and were looking to get this into a variable in a Linux-based bash script, try this:
VAR=$(shuf -i 200-700 -n 1)
That gets you the range of 200 to 700 into $VAR, inclusive.

Here's another one. I thought it would work on just about anything, but sort's random option isn't available on my centos box at work.
seq 2000 65000 | sort -R | head -n 1

Same with ruby:
echo $(ruby -e 'puts rand(20..65)') #=> 65 (inclusive ending)
echo $(ruby -e 'puts rand(20...65)') #=> 37 (exclusive ending)

Bash documentation says that every time $RANDOM is referenced, a random number between 0 and 32767 is returned. If we sum two consecutive references, we get values from 0 to 65534, which covers the desired range of 63001 possibilities for a random number between 2000 and 65000.
To adjust it to the exact range, we use the sum modulo 63001, which will give us a value from 0 to 63000. This in turn just needs an increment by 2000 to provide the desired random number, between 2000 and 65000. This can be summarized as follows:
port=$((((RANDOM + RANDOM) % 63001) + 2000))
Testing
# Generate random numbers and print the lowest and greatest found
test-random-max-min() {
max=2000
min=65000
for i in {1..10000}; do
port=$((((RANDOM + RANDOM) % 63001) + 2000))
echo -en "\r$port"
[[ "$port" -gt "$max" ]] && max="$port"
[[ "$port" -lt "$min" ]] && min="$port"
done
echo -e "\rMax: $max, min: $min"
}
# Sample output
# Max: 64990, min: 2002
# Max: 65000, min: 2004
# Max: 64970, min: 2000
Correctness of the calculation
Here is a full, brute-force test for the correctness of the calculation. This program just tries to generate all 63001 different possibilities randomly, using the calculation under test. The --jobs parameter should make it run faster, but it's not deterministic (total of possibilities generated may be lower than 63001).
test-all() {
start=$(date +%s)
find_start=$(date +%s)
total=0; ports=(); i=0
rm -f ports/ports.* ports.*
mkdir -p ports
while [[ "$total" -lt "$2" && "$all_found" != "yes" ]]; do
port=$((((RANDOM + RANDOM) % 63001) + 2000)); i=$((i+1))
if [[ -z "${ports[port]}" ]]; then
ports["$port"]="$port"
total=$((total + 1))
if [[ $((total % 1000)) == 0 ]]; then
echo -en "Elapsed time: $(($(date +%s) - find_start))s \t"
echo -e "Found: $port \t\t Total: $total\tIteration: $i"
find_start=$(date +%s)
fi
fi
done
all_found="yes"
echo "Job $1 finished after $i iterations in $(($(date +%s) - start))s."
out="ports.$1.txt"
[[ "$1" != "0" ]] && out="ports/$out"
echo "${ports[#]}" > "$out"
}
say-total() {
generated_ports=$(cat "$#" | tr ' ' '\n' | \sed -E s/'^([0-9]{4})$'/'0\1'/)
echo "Total generated: $(echo "$generated_ports" | sort | uniq | wc -l)."
}
total-single() { say-total "ports.0.txt"; }
total-jobs() { say-total "ports/"*; }
all_found="no"
[[ "$1" != "--jobs" ]] && test-all 0 63001 && total-single && exit
for i in {1..1000}; do test-all "$i" 40000 & sleep 1; done && wait && total-jobs
For determining how many iterations are needed to get a given probability p/q of all 63001 possibilities having been generated, I believe we can use the expression below. For example, here is the calculation for a probability greater than 1/2, and here for greater than 9/10.

$RANDOM is a number between 0 and 32767. You want a port between 2000 and 65000. These are 63001 possible ports. If we stick to values of $RANDOM + 2000 between 2000 and 33500, we cover a range of 31501 ports. If we flip a coin and then conditionally add 31501 to the result, we can get more ports, from 33501 to 65001. Then if we just drop 65001, we get the exact coverage needed, with a uniform probability distribution for all ports, it seems.
random-port() {
while [[ not != found ]]; do
# 2000..33500
port=$((RANDOM + 2000))
while [[ $port -gt 33500 ]]; do
port=$((RANDOM + 2000))
done
# 2000..65001
[[ $((RANDOM % 2)) = 0 ]] && port=$((port + 31501))
# 2000..65000
[[ $port = 65001 ]] && continue
echo $port
break
done
}
Testing
i=0
while true; do
i=$((i + 1))
printf "\rIteration $i..."
printf "%05d\n" $(random-port) >> ports.txt
done
# Then later we check the distribution
sort ports.txt | uniq -c | sort -r

You can do this
cat /dev/urandom|od -N2 -An -i|awk -v f=2000 -v r=65000 '{printf "%i\n", f + r * $1 / 65536}'
If you need more details see Shell Script Random Number Generator.

PORT=$(($RANDOM%63000+2001)) is close to what you want I think.
PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001)) gets around the size limitation that troubles you. Since bash makes no distinctions between a number variable and a string variable, this works perfectly well. The "number" $RANDOM can be concatenated like a string, and then used as a number in a calculation. Amazing!

Or on OS-X the following works for me:
$ gsort --random-sort

Generate random numbers in the range [$floor,$ceil), no dependence:
$(((RANDOM % $(($ceil- $floor))) + $floor))
Generate 100 numbers between 2000 to 65000:
for i in $(seq 100); do echo $(((RANDOM % $((65000 - 2000))) + 2000));done

You can get the random number through urandom
head -200 /dev/urandom | cksum
Output:
3310670062 52870
To retrieve the one part of the above number.
head -200 /dev/urandom | cksum | cut -f1 -d " "
Then the output is
3310670062
To meet your requirement,
head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'

This is how I usually generate random numbers. Then I use "NUM_1" as the variable for the port number I use. Here is a short example script.
#!/bin/bash
clear
echo 'Choose how many digits you want for port# (1-5)'
read PORT
NUM_1="$(tr -dc '0-9' </dev/urandom | head -c $PORT)"
echo "$NUM_1"
if [ "$PORT" -gt "5" ]
then
clear
echo -e "\x1b[31m Choose a number between 1 and 5! \x1b[0m"
sleep 3
clear
exit 0
fi

This works for me:
export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))
you can add 1 if you want it to start from 1 instead of 0.

Generating 50 numbers in Bash from a range 100000000000-999999999999 and saving them into a file filename.csv
shuf -i 100000000000-999999999999 -n 50 -o filename.csv

If you need a range bigger than 15 bit, dont use the slow unsecure and outdated 15 bit RANDOM, use the fast and secure 32 bit SRANDOM.
SRANDOM are available since about 2021 bash 5.1 roll out.
"one interesting addition to note with Bash 5.1 is the new SRANDOM variable. The SRANDOM variable provides random data from the system's entropy engine and cannot be reseeded. In particular, the SRANDOM variable provides a 32-bit random number that relies upon getrandom/getentropy -- with fall-backs to /dev/urandom or arc4random or even another fallback after that if necessary."
Source: https://www.phoronix.com/news/GNU-Bash-5.1
See what are the different of RANDOM and SRANDOM in bash:
Difference between RANDOM and SRANDOM in Bash
Feel free to improve this answer.

Related

bash shell script printf decimal 3 places not working [duplicate]

I am trying to divide two image widths in a Bash script, but bash gives me 0 as the result:
RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))
I did study the Bash guide and I know I should use bc, in all examples in internet they use bc. In echo I tried to put the same thing in my SCALE but it didn't work.
Here is the example I found in the tutorials:
echo "scale=2; ${userinput}" | bc
How can I get Bash to give me a float like 0.5?
You can't. bash only does integers; you must delegate to a tool such as bc.
you can do this:
bc <<< 'scale=2; 100/3'
33.33
UPDATE 20130926 : you can use:
bc -l <<< '100/3' # saves a few hits
33.33333333333333333333
bash
As noted by others, bash does not support floating point arithmetic, although you could fake it with some fixed decimal trickery, e.g. with two decimals:
echo $(( 100 * 1 / 3 )) | sed -e 's/..$/.&/;t' -e 's/.$/.0&/'
Output:
.33
See Nilfred's answer for a similar but more concise approach.
Alternatives
Besides the mentioned bc and awk alternatives there are also the following:
clisp
clisp -x '(/ 1.0 3)'
with cleaned up output:
clisp --quiet -x '(/ 1.0 3)'
or through stdin:
echo '(/ 1.0 3)' | clisp --quiet | tail -n1
dc
echo 2k 1 3 /p | dc
genius cli calculator
echo 1/3.0 | genius
ghostscript
echo 1 3 div = | gs -dNODISPLAY -dQUIET | sed -n '1s/.*>//p'
gnuplot
echo 'pr 1/3.' | gnuplot
Imagemagick
convert xc: -format '%[fx:1/3]' info:
or through stdin:
echo 1/3 | { convert xc: -format "%[fx:$(cat)]" info:; }
jq
jq -n 1/3
or through stdin:
echo 1/3 | jq -nf /dev/stdin
ksh
echo 'print $(( 1/3. ))' | ksh
lua
lua -e 'print(1/3)'
or through stdin:
echo 'print(1/3)' | lua
maxima
echo '1/3,numer;' | maxima
with cleaned up output:
echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'
node
echo 1/3 | node -p
octave
echo 1/3 | octave
perl
echo print 1/3 | perl
python2
echo print 1/3. | python2
python3
echo 'print(1/3)' | python3
R
echo 1/3 | R --no-save
with cleaned up output:
echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'
ruby
echo puts 1/3.0 | ruby
units
units 1/3
with compact output:
units --com 1/3
wcalc
echo 1/3 | wcalc
with cleaned up output:
echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2
zsh
print $(( 1/3. ))
or through stdin:
echo 'print $(( 1/3. ))' | zsh
Other sources
Stéphane Chazelas answered a similar question over on UL.
Improving a little the answer of marvin:
RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")
bc doesn't come always as installed package.
You could use bc by the -l option (the L letter)
RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)
As an alternative to bc, you can use awk within your script.
For example:
echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'
In the above, " %.2f " tells the printf function to return a floating point number with two digits after the decimal place. I used echo to pipe in the variables as fields since awk operates properly on them. " $1 " and " $2 " refer to the first and second fields input into awk.
And you can store the result as some other variable using:
RESULT = `echo ...`
Well, before float was a time where fixed decimals logic was used:
IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33
Last line is a bashim, if not using bash, try this code instead:
IMG_WIDTH=100
IMG2_WIDTH=3
INTEGER=$(($IMG_WIDTH/$IMG2_WIDTH))
DECIMAL=$(tail -c 3 <<< $((${IMG_WIDTH}00/$IMG2_WIDTH)))
RESULT=$INTEGER.$DECIMAL
echo $RESULT
33.33
The rationale behind the code is: multiply by 100 before divide to get 2 decimals.
It's perfect time to try zsh, an (almost) bash superset, with many additional nice features including floating point math. Here is what your example would be like in zsh:
% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875
This post may help you: bash - Worth switching to zsh for casual use?
If you found the variant of your preference you can also wrap it into a function.
Here I'm wrapping some bashism into a div function:
One liner:
function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}
Or multi line:
function div {
local _d=${3:-2}
local _n=0000000000
_n=${_n:0:$_d}
local _r=$(($1$_n/$2))
_r=${_r:0:-$_d}.${_r: -$_d}
echo $_r
}
Now you have the function
div <dividend> <divisor> [<precision=2>]
and use it like
> div 1 2
.50
> div 273 123 5
2.21951
> x=$(div 22 7)
> echo $x
3.14
UPDATE
I added a little script which provides you the basic operations with floating point numbers for bash:
Usage:
> add 1.2 3.45
4.65
> sub 1000 .007
999.993
> mul 1.1 7.07
7.7770
> div 10 3
3.
> div 10 3.000
3.333
And here the script:
#!/bin/bash
__op() {
local z=00000000000000000000000000000000
local a1=${1%.*}
local x1=${1//./}
local n1=$((${#x1}-${#a1}))
local a2=${2%.*}
local x2=${2//./}
local n2=$((${#x2}-${#a2}))
local n=$n1
if (($n1 < $n2)); then
local n=$n2
x1=$x1${z:0:$(($n2-$n1))}
fi
if (($n1 > $n2)); then
x2=$x2${z:0:$(($n1-$n2))}
fi
if [ "$3" == "/" ]; then
x1=$x1${z:0:$n}
fi
local r=$(($x1"$3"$x2))
local l=$((${#r}-$n))
if [ "$3" == "*" ]; then
l=$(($l-$n))
fi
echo ${r:0:$l}.${r:$l}
}
add() { __op $1 $2 + ;}
sub() { __op $1 $2 - ;}
mul() { __op $1 $2 "*" ;}
div() { __op $1 $2 / ;}
How to do floating point calculations in bash:
Instead of using "here strings" (<<<) with the bc command, like one of the most-upvoted examples does, here's my favorite bc floating point example, right from the EXAMPLES section of the bc man pages (see man bc for the manual pages).
Before we begin, know that an equation for pi is: pi = 4*atan(1). a() below is the bc math function for atan().
This is how to store the result of a floating point calculation into a bash variable--in this case into a variable called pi. Note that scale=10 sets the number of decimal digits of precision to 10 in this case. Any decimal digits after this place are truncated.
pi=$(echo "scale=10; 4*a(1)" | bc -l)
Now, to have a single line of code that also prints out the value of this variable, simply add the echo command to the end as a follow-up command, as follows. Note the truncation at 10 decimal places, as commanded:
pi=$(echo "scale=10; 4*a(1)" | bc -l); echo $pi
3.1415926532
Finally, let's throw in some rounding. Here we will use the printf function to round to 4 decimal places. Note that the 3.14159... rounds now to 3.1416. Since we are rounding, we no longer need to use scale=10 to truncate to 10 decimal places, so we'll just remove that part. Here's the end solution:
pi=$(printf %.4f $(echo "4*a(1)" | bc -l)); echo $pi
3.1416
Here's another really great application and demo of the above techniques: measuring and printing run-time.
(See also my other answer here).
Note that dt_min gets rounded from 0.01666666666... to 0.017:
start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); echo "dt_sec = $dt_sec; dt_min = $dt_min"
dt_sec = 1; dt_min = 0.017
Related:
[my answer] https://unix.stackexchange.com/questions/52313/how-to-get-execution-time-of-a-script-effectively/547849#547849
[my question] What do three left angle brackets (`<<<`) mean in bash?
https://unix.stackexchange.com/questions/80362/what-does-mean/80368#80368
https://askubuntu.com/questions/179898/how-to-round-decimals-using-bc-in-bash/574474#574474
While you can't use floating point division in Bash you can use fixed point division. All that you need to do is multiply your integers by a power of 10 and then divide off the integer part and use a modulo operation to get the fractional part. Rounding as needed.
#!/bin/bash
n=$1
d=$2
# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))
I know it's old, but too tempting. So, the answer is: you can't... but you kind of can. let's try this:
$IMG_WIDTH=1024
$IMG2_WIDTH=2048
$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))"
Like that, you get 2 digits after the point, truncated (call it rounding to the lower) in pure bash (no need to launch other processes). Of course, if you only need one digit after the point you multiply by 10 and do modulo 10.
What this does:
first $((...)) does integer division;
second $((...)) does integer division on something 100 times larger, essentially moving your 2 digits to the left of the point, then (%) getting you only those 2 digits by doing modulo.
Bonus track: bc version × 1000 took 1.8 seconds on my laptop, while the pure bash one took 0.016 seconds.
It's not really floating point, but if you want something that sets more than one result in one invocation of bc...
source /dev/stdin <<<$(bc <<< '
d='$1'*3.1415926535897932384626433832795*2
print "d=",d,"\n"
a='$1'*'$1'*3.1415926535897932384626433832795
print "a=",a,"\n"
')
echo bc radius:$1 area:$a diameter:$d
computes the area and diameter of a circle whose radius is given in $1
There are scenarios in wich you cannot use bc becouse it might simply not be present, like in some cut down versions of busybox or embedded systems. In any case limiting outer dependencies is always a good thing to do so you can always add zeroes to the number being divided by (numerator), that is the same as multiplying by a power of 10 (you should choose a power of 10 according to the precision you need), that will make the division output an integer number. Once you have that integer treat it as a string and position the decimal point (moving it from right to left) a number of times equal to the power of ten you multiplied the numerator by. This is a simple way of obtaining float results by using only integer numbers.
For those trying to calculate percentages with the accepted answer, but are losing precision:
If you run this:
echo "scale=2; (100/180) * 180" | bc
You get 99.00 only, which is losing precision.
If you run it this way:
echo "result = (100/180) * 180; scale=2; result / 1" | bc -l
Now you get 99.99.
Because you're scaling only at the moment of printing.
Refer to here
Use calc. It's the easiest I found
example:
calc 1+1
2
calc 1/10
0.1
** Injection-safe floating point math in bash/shell **
Note: The focus of this answer is provide ideas for injection-safe solution to performing math in bash (or other shells). Of course, same can be used, with minor adjustment to perform advanced string processing, etc.
Most of the solution that were by presented, construct small scriptlet on the fly, using external data (variables, files, command line, environment variables). The external input can be used to inject malicious code into the engine, many of them
Below is a comparison on using the various language to perform basic math calculation, where the result in floating point. It calculates A + B * 0.1 (as floating point).
All solution attempt avoid creating dynamic scriptlets, which are extremely hard to maintain, Instead they use static program, and pass parameters into designated variable. They will safely handle parameters with special characters - reducing the possibility of code injection. The exception is 'BC' which does not provide input/output facility
The exception is 'bc', which does not provide any input/output, all the data comes via programs in stdin, and all output goes to stdout. All calculation are executing in a sandbox, which does not allow side effect (opening files, etc.). In theory, injection safe by design!
A=5.2
B=4.3
# Awk: Map variable into awk
# Exit 0 (or just exit) for success, non-zero for error.
#
awk -v A="$A" -v B="$B" 'BEGIN { print A + B * 0.1 ; exit 0}'
# Perl
perl -e '($A,$B) = #ARGV ; print $A + $B * 0.1' "$A" "$B"
# Python 2
python -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print a+b*0.1' "$A" "$B"
# Python 3
python3 -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print(a+b*0.1)' "$A" "$B"
# BC
bc <<< "scale=1 ; $A + $B * 0.1"
As others have indicated, bash does not have built-in floating-point operators.
You can implement floating-point in bash, even without using calculator programs like bc and awk, or any external programs for that matter.
I'm doing exactly this in my project, shellmath, in three basic steps:
Break the numbers down into their integer and fractional parts
Use the built-in integer operators to process the parts separately while being careful about place-value and carrying
Recombine the results
As a teaser, I've added a demo script that calculates e using its Taylor series centered at x=0.
Please check it out if you have a moment. I welcome your feedback!
Bash can calculate floating point results just fine without any other programs.
Bash independently even can calculate π to the ninth decimal place accurately.
Example:
calc=104348/33215
accuracy=9
calc99p9=$((10**$accuracy))*$calc
result99p9=$((calc99p9))
result=${result99p9: -${#result99p9}: -$accuracy}.${result99p9: -$accuracy}
echo Bash calculated pi to be $result
results in
Bash calculated pi to be 3.141592653
Dividend = Divisor × Quotient + Remainder
Lets just calculate the quotient and remainder.
As well as concatenate those strings in a variable.
New way valid only to log_decimal divisors:
function main() {
bar=10030
divisor=100
# divisor=50
quotient=$((bar / divisor))
# remainder=$((bar - v_int * divisor))
remainder=$((bar % divisor))
remainder_init=$remainder
printf "%-15s --> %s\n" "quotient" "$quotient"
printf "%-15s --> %s\n" "remainder" "$remainder"
cnt=0
while :; do
remainder=$((remainder * 10))
aux=$((remainder / divisor))
printf "%-15s --> %s\n" "aux" "$aux"
[[ aux -ne 0 ]] && break
((cnt += 1))
printf "%-15s --> %s\n" "remainder" "$remainder"
done
printf "%-15s --> %s\n" "cnt" "$cnt"
printf "%-15s --> %s\n" "aux" "$aux"
printf $quotient
printf "."
for i in $(seq 1 $cnt); do printf "0"; done
printf $remainder_init
}
clear
main
Old wrong way:
bar=1234 \
&& divisor=1000 \
&& foo=$(printf "%s.%s" $(( bar / divisor )) $(( bar % divisor ))) \
&& printf "bar is %d miliseconds or %s seconds\n" $bar $foo
Output: bar is 1234 miliseconds or 1.234 seconds
here is awk command: -F = field separator == +
echo "2.1+3.1" | awk -F "+" '{print ($1+$2)}'
how precise do you need the output to be ? if an approximation via binning is already acceptable for your use case, you can even go one step further and take advantage of POSIX exit codes [0:256) (all other integers mod'd back to that range).
eg : in gawk/nawk/mawk-1, it already gives me epoch seconds down to the integer level, but I wanted to expand that to extract near-milliseconds precision but not overly pedantic about it, i run this command in a POSIX shell
exit $(( 10#` gdate +%5N ` * 256 / 100000 ))
directly assigning a 5-digit integer representing 0.xxxxxx output of gnu-date into 1 of 256 bins, then un-doing that 256 once awk obtains the exit code of the system() call, i.e. the selected bin #. I found this approach to have lower overhead than using a full getline call.
This method also directly captures the output into the POSIX exit code instead of also having an extra terminal print out.
(the shell arithmetic auto floors it to integer if written this way instead of * 0.0256). Putting together into an awk function, it would resemble this. The 10# is to force base-10 to prevent posix shell interpreting "01733" as an octal number.
function msecs() { # n x 2**-8 = n divided by 256
return 2^-8 * \
system( "exit \44\50\50 " \
" 10\43\140 gdate \53" \
"%5N\140 \52 " \
"256 \57 100000 \51\51" )
}
for my own code, i apply another 0.6% haircut to account for shell-overhead.
Let us take an example to undertsand, if u want to find average of n array elements (Ofcourse the average will be in float/decimals)
declare -a arr
echo "How many numbers you want to enter?"
read n
echo "Enter the Array Elements"
for(( i=0 ; i<$n ; i++))
do
read array_elements
arr[$i]="$array_elements"
done
sum=0
for i in "${arr[#]}"
do
#sum and avg
sum=$(($sum + $i))
#average will come in decimals
avg=`echo $sum / $n | bc -l`
done
# Output results:
printf "Average of Array Elements %.2f:" $avg
So we will use "| bc -l" to do floating calculations

how can I generate random numbers in specific range in bash using $RANDOM? [duplicate]

I need to generate a random port number between 2000-65000 from a shell script. The problem is $RANDOM is a 15-bit number, so I'm stuck!
PORT=$(($RANDOM%63000+2001)) would work nicely if it wasn't for the size limitation.
Does anyone have an example of how I can do this, maybe by extracting something from /dev/urandom and getting it within a range?
shuf -i 2000-65000 -n 1
Enjoy!
Edit: The range is inclusive.
On Mac OS X and FreeBSD you may also use jot:
jot -r 1 2000 65000
According to the bash man page, $RANDOM is distributed between 0 and 32767; that is, it is an unsigned 15-bit value. Assuming $RANDOM is uniformly distributed, you can create a uniformly-distributed unsigned 30-bit integer as follows:
$(((RANDOM<<15)|RANDOM))
Since your range is not a power of 2, a simple modulo operation will only almost give you a uniform distribution, but with a 30-bit input range and a less-than-16-bit output range, as you have in your case, this should really be close enough:
PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 ))
and here's one with Python
randport=$(python -S -c "import random; print random.randrange(2000,63000)")
and one with awk
awk 'BEGIN{srand();print int(rand()*(63000-2000))+2000 }'
The simplest general way that comes to mind is a perl one-liner:
perl -e 'print int(rand(65000-2000)) + 2000'
You could always just use two numbers:
PORT=$(($RANDOM + ($RANDOM % 2) * 32768))
You still have to clip to your range. It's not a general n-bit random number method, but it'll work for your case, and it's all inside bash.
If you want to be really cute and read from /dev/urandom, you could do this:
od -A n -N 2 -t u2 /dev/urandom
That'll read two bytes and print them as an unsigned int; you still have to do your clipping.
If you're not a bash expert and were looking to get this into a variable in a Linux-based bash script, try this:
VAR=$(shuf -i 200-700 -n 1)
That gets you the range of 200 to 700 into $VAR, inclusive.
Here's another one. I thought it would work on just about anything, but sort's random option isn't available on my centos box at work.
seq 2000 65000 | sort -R | head -n 1
Same with ruby:
echo $(ruby -e 'puts rand(20..65)') #=> 65 (inclusive ending)
echo $(ruby -e 'puts rand(20...65)') #=> 37 (exclusive ending)
Bash documentation says that every time $RANDOM is referenced, a random number between 0 and 32767 is returned. If we sum two consecutive references, we get values from 0 to 65534, which covers the desired range of 63001 possibilities for a random number between 2000 and 65000.
To adjust it to the exact range, we use the sum modulo 63001, which will give us a value from 0 to 63000. This in turn just needs an increment by 2000 to provide the desired random number, between 2000 and 65000. This can be summarized as follows:
port=$((((RANDOM + RANDOM) % 63001) + 2000))
Testing
# Generate random numbers and print the lowest and greatest found
test-random-max-min() {
max=2000
min=65000
for i in {1..10000}; do
port=$((((RANDOM + RANDOM) % 63001) + 2000))
echo -en "\r$port"
[[ "$port" -gt "$max" ]] && max="$port"
[[ "$port" -lt "$min" ]] && min="$port"
done
echo -e "\rMax: $max, min: $min"
}
# Sample output
# Max: 64990, min: 2002
# Max: 65000, min: 2004
# Max: 64970, min: 2000
Correctness of the calculation
Here is a full, brute-force test for the correctness of the calculation. This program just tries to generate all 63001 different possibilities randomly, using the calculation under test. The --jobs parameter should make it run faster, but it's not deterministic (total of possibilities generated may be lower than 63001).
test-all() {
start=$(date +%s)
find_start=$(date +%s)
total=0; ports=(); i=0
rm -f ports/ports.* ports.*
mkdir -p ports
while [[ "$total" -lt "$2" && "$all_found" != "yes" ]]; do
port=$((((RANDOM + RANDOM) % 63001) + 2000)); i=$((i+1))
if [[ -z "${ports[port]}" ]]; then
ports["$port"]="$port"
total=$((total + 1))
if [[ $((total % 1000)) == 0 ]]; then
echo -en "Elapsed time: $(($(date +%s) - find_start))s \t"
echo -e "Found: $port \t\t Total: $total\tIteration: $i"
find_start=$(date +%s)
fi
fi
done
all_found="yes"
echo "Job $1 finished after $i iterations in $(($(date +%s) - start))s."
out="ports.$1.txt"
[[ "$1" != "0" ]] && out="ports/$out"
echo "${ports[#]}" > "$out"
}
say-total() {
generated_ports=$(cat "$#" | tr ' ' '\n' | \sed -E s/'^([0-9]{4})$'/'0\1'/)
echo "Total generated: $(echo "$generated_ports" | sort | uniq | wc -l)."
}
total-single() { say-total "ports.0.txt"; }
total-jobs() { say-total "ports/"*; }
all_found="no"
[[ "$1" != "--jobs" ]] && test-all 0 63001 && total-single && exit
for i in {1..1000}; do test-all "$i" 40000 & sleep 1; done && wait && total-jobs
For determining how many iterations are needed to get a given probability p/q of all 63001 possibilities having been generated, I believe we can use the expression below. For example, here is the calculation for a probability greater than 1/2, and here for greater than 9/10.
$RANDOM is a number between 0 and 32767. You want a port between 2000 and 65000. These are 63001 possible ports. If we stick to values of $RANDOM + 2000 between 2000 and 33500, we cover a range of 31501 ports. If we flip a coin and then conditionally add 31501 to the result, we can get more ports, from 33501 to 65001. Then if we just drop 65001, we get the exact coverage needed, with a uniform probability distribution for all ports, it seems.
random-port() {
while [[ not != found ]]; do
# 2000..33500
port=$((RANDOM + 2000))
while [[ $port -gt 33500 ]]; do
port=$((RANDOM + 2000))
done
# 2000..65001
[[ $((RANDOM % 2)) = 0 ]] && port=$((port + 31501))
# 2000..65000
[[ $port = 65001 ]] && continue
echo $port
break
done
}
Testing
i=0
while true; do
i=$((i + 1))
printf "\rIteration $i..."
printf "%05d\n" $(random-port) >> ports.txt
done
# Then later we check the distribution
sort ports.txt | uniq -c | sort -r
You can do this
cat /dev/urandom|od -N2 -An -i|awk -v f=2000 -v r=65000 '{printf "%i\n", f + r * $1 / 65536}'
If you need more details see Shell Script Random Number Generator.
PORT=$(($RANDOM%63000+2001)) is close to what you want I think.
PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001)) gets around the size limitation that troubles you. Since bash makes no distinctions between a number variable and a string variable, this works perfectly well. The "number" $RANDOM can be concatenated like a string, and then used as a number in a calculation. Amazing!
Or on OS-X the following works for me:
$ gsort --random-sort
Generate random numbers in the range [$floor,$ceil), no dependence:
$(((RANDOM % $(($ceil- $floor))) + $floor))
Generate 100 numbers between 2000 to 65000:
for i in $(seq 100); do echo $(((RANDOM % $((65000 - 2000))) + 2000));done
You can get the random number through urandom
head -200 /dev/urandom | cksum
Output:
3310670062 52870
To retrieve the one part of the above number.
head -200 /dev/urandom | cksum | cut -f1 -d " "
Then the output is
3310670062
To meet your requirement,
head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'
This is how I usually generate random numbers. Then I use "NUM_1" as the variable for the port number I use. Here is a short example script.
#!/bin/bash
clear
echo 'Choose how many digits you want for port# (1-5)'
read PORT
NUM_1="$(tr -dc '0-9' </dev/urandom | head -c $PORT)"
echo "$NUM_1"
if [ "$PORT" -gt "5" ]
then
clear
echo -e "\x1b[31m Choose a number between 1 and 5! \x1b[0m"
sleep 3
clear
exit 0
fi
This works for me:
export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))
you can add 1 if you want it to start from 1 instead of 0.
Generating 50 numbers in Bash from a range 100000000000-999999999999 and saving them into a file filename.csv
shuf -i 100000000000-999999999999 -n 50 -o filename.csv
If you need a range bigger than 15 bit, dont use the slow unsecure and outdated 15 bit RANDOM, use the fast and secure 32 bit SRANDOM.
SRANDOM are available since about 2021 bash 5.1 roll out.
"one interesting addition to note with Bash 5.1 is the new SRANDOM variable. The SRANDOM variable provides random data from the system's entropy engine and cannot be reseeded. In particular, the SRANDOM variable provides a 32-bit random number that relies upon getrandom/getentropy -- with fall-backs to /dev/urandom or arc4random or even another fallback after that if necessary."
Source: https://www.phoronix.com/news/GNU-Bash-5.1
See what are the different of RANDOM and SRANDOM in bash:
Difference between RANDOM and SRANDOM in Bash
Feel free to improve this answer.

Multiplying integer and float variables in bash [duplicate]

I am trying to divide two image widths in a Bash script, but bash gives me 0 as the result:
RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))
I did study the Bash guide and I know I should use bc, in all examples in internet they use bc. In echo I tried to put the same thing in my SCALE but it didn't work.
Here is the example I found in the tutorials:
echo "scale=2; ${userinput}" | bc
How can I get Bash to give me a float like 0.5?
You can't. bash only does integers; you must delegate to a tool such as bc.
you can do this:
bc <<< 'scale=2; 100/3'
33.33
UPDATE 20130926 : you can use:
bc -l <<< '100/3' # saves a few hits
33.33333333333333333333
bash
As noted by others, bash does not support floating point arithmetic, although you could fake it with some fixed decimal trickery, e.g. with two decimals:
echo $(( 100 * 1 / 3 )) | sed -e 's/..$/.&/;t' -e 's/.$/.0&/'
Output:
.33
See Nilfred's answer for a similar but more concise approach.
Alternatives
Besides the mentioned bc and awk alternatives there are also the following:
clisp
clisp -x '(/ 1.0 3)'
with cleaned up output:
clisp --quiet -x '(/ 1.0 3)'
or through stdin:
echo '(/ 1.0 3)' | clisp --quiet | tail -n1
dc
echo 2k 1 3 /p | dc
genius cli calculator
echo 1/3.0 | genius
ghostscript
echo 1 3 div = | gs -dNODISPLAY -dQUIET | sed -n '1s/.*>//p'
gnuplot
echo 'pr 1/3.' | gnuplot
Imagemagick
convert xc: -format '%[fx:1/3]' info:
or through stdin:
echo 1/3 | { convert xc: -format "%[fx:$(cat)]" info:; }
jq
jq -n 1/3
or through stdin:
echo 1/3 | jq -nf /dev/stdin
ksh
echo 'print $(( 1/3. ))' | ksh
lua
lua -e 'print(1/3)'
or through stdin:
echo 'print(1/3)' | lua
maxima
echo '1/3,numer;' | maxima
with cleaned up output:
echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'
node
echo 1/3 | node -p
octave
echo 1/3 | octave
perl
echo print 1/3 | perl
python2
echo print 1/3. | python2
python3
echo 'print(1/3)' | python3
R
echo 1/3 | R --no-save
with cleaned up output:
echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'
ruby
echo puts 1/3.0 | ruby
units
units 1/3
with compact output:
units --com 1/3
wcalc
echo 1/3 | wcalc
with cleaned up output:
echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2
zsh
print $(( 1/3. ))
or through stdin:
echo 'print $(( 1/3. ))' | zsh
Other sources
Stéphane Chazelas answered a similar question over on UL.
Improving a little the answer of marvin:
RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")
bc doesn't come always as installed package.
You could use bc by the -l option (the L letter)
RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)
As an alternative to bc, you can use awk within your script.
For example:
echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'
In the above, " %.2f " tells the printf function to return a floating point number with two digits after the decimal place. I used echo to pipe in the variables as fields since awk operates properly on them. " $1 " and " $2 " refer to the first and second fields input into awk.
And you can store the result as some other variable using:
RESULT = `echo ...`
Well, before float was a time where fixed decimals logic was used:
IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33
Last line is a bashim, if not using bash, try this code instead:
IMG_WIDTH=100
IMG2_WIDTH=3
INTEGER=$(($IMG_WIDTH/$IMG2_WIDTH))
DECIMAL=$(tail -c 3 <<< $((${IMG_WIDTH}00/$IMG2_WIDTH)))
RESULT=$INTEGER.$DECIMAL
echo $RESULT
33.33
The rationale behind the code is: multiply by 100 before divide to get 2 decimals.
It's perfect time to try zsh, an (almost) bash superset, with many additional nice features including floating point math. Here is what your example would be like in zsh:
% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875
This post may help you: bash - Worth switching to zsh for casual use?
If you found the variant of your preference you can also wrap it into a function.
Here I'm wrapping some bashism into a div function:
One liner:
function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}
Or multi line:
function div {
local _d=${3:-2}
local _n=0000000000
_n=${_n:0:$_d}
local _r=$(($1$_n/$2))
_r=${_r:0:-$_d}.${_r: -$_d}
echo $_r
}
Now you have the function
div <dividend> <divisor> [<precision=2>]
and use it like
> div 1 2
.50
> div 273 123 5
2.21951
> x=$(div 22 7)
> echo $x
3.14
UPDATE
I added a little script which provides you the basic operations with floating point numbers for bash:
Usage:
> add 1.2 3.45
4.65
> sub 1000 .007
999.993
> mul 1.1 7.07
7.7770
> div 10 3
3.
> div 10 3.000
3.333
And here the script:
#!/bin/bash
__op() {
local z=00000000000000000000000000000000
local a1=${1%.*}
local x1=${1//./}
local n1=$((${#x1}-${#a1}))
local a2=${2%.*}
local x2=${2//./}
local n2=$((${#x2}-${#a2}))
local n=$n1
if (($n1 < $n2)); then
local n=$n2
x1=$x1${z:0:$(($n2-$n1))}
fi
if (($n1 > $n2)); then
x2=$x2${z:0:$(($n1-$n2))}
fi
if [ "$3" == "/" ]; then
x1=$x1${z:0:$n}
fi
local r=$(($x1"$3"$x2))
local l=$((${#r}-$n))
if [ "$3" == "*" ]; then
l=$(($l-$n))
fi
echo ${r:0:$l}.${r:$l}
}
add() { __op $1 $2 + ;}
sub() { __op $1 $2 - ;}
mul() { __op $1 $2 "*" ;}
div() { __op $1 $2 / ;}
How to do floating point calculations in bash:
Instead of using "here strings" (<<<) with the bc command, like one of the most-upvoted examples does, here's my favorite bc floating point example, right from the EXAMPLES section of the bc man pages (see man bc for the manual pages).
Before we begin, know that an equation for pi is: pi = 4*atan(1). a() below is the bc math function for atan().
This is how to store the result of a floating point calculation into a bash variable--in this case into a variable called pi. Note that scale=10 sets the number of decimal digits of precision to 10 in this case. Any decimal digits after this place are truncated.
pi=$(echo "scale=10; 4*a(1)" | bc -l)
Now, to have a single line of code that also prints out the value of this variable, simply add the echo command to the end as a follow-up command, as follows. Note the truncation at 10 decimal places, as commanded:
pi=$(echo "scale=10; 4*a(1)" | bc -l); echo $pi
3.1415926532
Finally, let's throw in some rounding. Here we will use the printf function to round to 4 decimal places. Note that the 3.14159... rounds now to 3.1416. Since we are rounding, we no longer need to use scale=10 to truncate to 10 decimal places, so we'll just remove that part. Here's the end solution:
pi=$(printf %.4f $(echo "4*a(1)" | bc -l)); echo $pi
3.1416
Here's another really great application and demo of the above techniques: measuring and printing run-time.
(See also my other answer here).
Note that dt_min gets rounded from 0.01666666666... to 0.017:
start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); echo "dt_sec = $dt_sec; dt_min = $dt_min"
dt_sec = 1; dt_min = 0.017
Related:
[my answer] https://unix.stackexchange.com/questions/52313/how-to-get-execution-time-of-a-script-effectively/547849#547849
[my question] What do three left angle brackets (`<<<`) mean in bash?
https://unix.stackexchange.com/questions/80362/what-does-mean/80368#80368
https://askubuntu.com/questions/179898/how-to-round-decimals-using-bc-in-bash/574474#574474
While you can't use floating point division in Bash you can use fixed point division. All that you need to do is multiply your integers by a power of 10 and then divide off the integer part and use a modulo operation to get the fractional part. Rounding as needed.
#!/bin/bash
n=$1
d=$2
# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))
I know it's old, but too tempting. So, the answer is: you can't... but you kind of can. let's try this:
$IMG_WIDTH=1024
$IMG2_WIDTH=2048
$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))"
Like that, you get 2 digits after the point, truncated (call it rounding to the lower) in pure bash (no need to launch other processes). Of course, if you only need one digit after the point you multiply by 10 and do modulo 10.
What this does:
first $((...)) does integer division;
second $((...)) does integer division on something 100 times larger, essentially moving your 2 digits to the left of the point, then (%) getting you only those 2 digits by doing modulo.
Bonus track: bc version × 1000 took 1.8 seconds on my laptop, while the pure bash one took 0.016 seconds.
It's not really floating point, but if you want something that sets more than one result in one invocation of bc...
source /dev/stdin <<<$(bc <<< '
d='$1'*3.1415926535897932384626433832795*2
print "d=",d,"\n"
a='$1'*'$1'*3.1415926535897932384626433832795
print "a=",a,"\n"
')
echo bc radius:$1 area:$a diameter:$d
computes the area and diameter of a circle whose radius is given in $1
There are scenarios in wich you cannot use bc becouse it might simply not be present, like in some cut down versions of busybox or embedded systems. In any case limiting outer dependencies is always a good thing to do so you can always add zeroes to the number being divided by (numerator), that is the same as multiplying by a power of 10 (you should choose a power of 10 according to the precision you need), that will make the division output an integer number. Once you have that integer treat it as a string and position the decimal point (moving it from right to left) a number of times equal to the power of ten you multiplied the numerator by. This is a simple way of obtaining float results by using only integer numbers.
For those trying to calculate percentages with the accepted answer, but are losing precision:
If you run this:
echo "scale=2; (100/180) * 180" | bc
You get 99.00 only, which is losing precision.
If you run it this way:
echo "result = (100/180) * 180; scale=2; result / 1" | bc -l
Now you get 99.99.
Because you're scaling only at the moment of printing.
Refer to here
Use calc. It's the easiest I found
example:
calc 1+1
2
calc 1/10
0.1
** Injection-safe floating point math in bash/shell **
Note: The focus of this answer is provide ideas for injection-safe solution to performing math in bash (or other shells). Of course, same can be used, with minor adjustment to perform advanced string processing, etc.
Most of the solution that were by presented, construct small scriptlet on the fly, using external data (variables, files, command line, environment variables). The external input can be used to inject malicious code into the engine, many of them
Below is a comparison on using the various language to perform basic math calculation, where the result in floating point. It calculates A + B * 0.1 (as floating point).
All solution attempt avoid creating dynamic scriptlets, which are extremely hard to maintain, Instead they use static program, and pass parameters into designated variable. They will safely handle parameters with special characters - reducing the possibility of code injection. The exception is 'BC' which does not provide input/output facility
The exception is 'bc', which does not provide any input/output, all the data comes via programs in stdin, and all output goes to stdout. All calculation are executing in a sandbox, which does not allow side effect (opening files, etc.). In theory, injection safe by design!
A=5.2
B=4.3
# Awk: Map variable into awk
# Exit 0 (or just exit) for success, non-zero for error.
#
awk -v A="$A" -v B="$B" 'BEGIN { print A + B * 0.1 ; exit 0}'
# Perl
perl -e '($A,$B) = #ARGV ; print $A + $B * 0.1' "$A" "$B"
# Python 2
python -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print a+b*0.1' "$A" "$B"
# Python 3
python3 -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print(a+b*0.1)' "$A" "$B"
# BC
bc <<< "scale=1 ; $A + $B * 0.1"
As others have indicated, bash does not have built-in floating-point operators.
You can implement floating-point in bash, even without using calculator programs like bc and awk, or any external programs for that matter.
I'm doing exactly this in my project, shellmath, in three basic steps:
Break the numbers down into their integer and fractional parts
Use the built-in integer operators to process the parts separately while being careful about place-value and carrying
Recombine the results
As a teaser, I've added a demo script that calculates e using its Taylor series centered at x=0.
Please check it out if you have a moment. I welcome your feedback!
Bash can calculate floating point results just fine without any other programs.
Bash independently even can calculate π to the ninth decimal place accurately.
Example:
calc=104348/33215
accuracy=9
calc99p9=$((10**$accuracy))*$calc
result99p9=$((calc99p9))
result=${result99p9: -${#result99p9}: -$accuracy}.${result99p9: -$accuracy}
echo Bash calculated pi to be $result
results in
Bash calculated pi to be 3.141592653
Dividend = Divisor × Quotient + Remainder
Lets just calculate the quotient and remainder.
As well as concatenate those strings in a variable.
New way valid only to log_decimal divisors:
function main() {
bar=10030
divisor=100
# divisor=50
quotient=$((bar / divisor))
# remainder=$((bar - v_int * divisor))
remainder=$((bar % divisor))
remainder_init=$remainder
printf "%-15s --> %s\n" "quotient" "$quotient"
printf "%-15s --> %s\n" "remainder" "$remainder"
cnt=0
while :; do
remainder=$((remainder * 10))
aux=$((remainder / divisor))
printf "%-15s --> %s\n" "aux" "$aux"
[[ aux -ne 0 ]] && break
((cnt += 1))
printf "%-15s --> %s\n" "remainder" "$remainder"
done
printf "%-15s --> %s\n" "cnt" "$cnt"
printf "%-15s --> %s\n" "aux" "$aux"
printf $quotient
printf "."
for i in $(seq 1 $cnt); do printf "0"; done
printf $remainder_init
}
clear
main
Old wrong way:
bar=1234 \
&& divisor=1000 \
&& foo=$(printf "%s.%s" $(( bar / divisor )) $(( bar % divisor ))) \
&& printf "bar is %d miliseconds or %s seconds\n" $bar $foo
Output: bar is 1234 miliseconds or 1.234 seconds
here is awk command: -F = field separator == +
echo "2.1+3.1" | awk -F "+" '{print ($1+$2)}'
how precise do you need the output to be ? if an approximation via binning is already acceptable for your use case, you can even go one step further and take advantage of POSIX exit codes [0:256) (all other integers mod'd back to that range).
eg : in gawk/nawk/mawk-1, it already gives me epoch seconds down to the integer level, but I wanted to expand that to extract near-milliseconds precision but not overly pedantic about it, i run this command in a POSIX shell
exit $(( 10#` gdate +%5N ` * 256 / 100000 ))
directly assigning a 5-digit integer representing 0.xxxxxx output of gnu-date into 1 of 256 bins, then un-doing that 256 once awk obtains the exit code of the system() call, i.e. the selected bin #. I found this approach to have lower overhead than using a full getline call.
This method also directly captures the output into the POSIX exit code instead of also having an extra terminal print out.
(the shell arithmetic auto floors it to integer if written this way instead of * 0.0256). Putting together into an awk function, it would resemble this. The 10# is to force base-10 to prevent posix shell interpreting "01733" as an octal number.
function msecs() { # n x 2**-8 = n divided by 256
return 2^-8 * \
system( "exit \44\50\50 " \
" 10\43\140 gdate \53" \
"%5N\140 \52 " \
"256 \57 100000 \51\51" )
}
for my own code, i apply another 0.6% haircut to account for shell-overhead.
Let us take an example to undertsand, if u want to find average of n array elements (Ofcourse the average will be in float/decimals)
declare -a arr
echo "How many numbers you want to enter?"
read n
echo "Enter the Array Elements"
for(( i=0 ; i<$n ; i++))
do
read array_elements
arr[$i]="$array_elements"
done
sum=0
for i in "${arr[#]}"
do
#sum and avg
sum=$(($sum + $i))
#average will come in decimals
avg=`echo $sum / $n | bc -l`
done
# Output results:
printf "Average of Array Elements %.2f:" $avg
So we will use "| bc -l" to do floating calculations

Echo floating point result from bc in shell? [duplicate]

I am trying to divide two image widths in a Bash script, but bash gives me 0 as the result:
RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))
I did study the Bash guide and I know I should use bc, in all examples in internet they use bc. In echo I tried to put the same thing in my SCALE but it didn't work.
Here is the example I found in the tutorials:
echo "scale=2; ${userinput}" | bc
How can I get Bash to give me a float like 0.5?
You can't. bash only does integers; you must delegate to a tool such as bc.
you can do this:
bc <<< 'scale=2; 100/3'
33.33
UPDATE 20130926 : you can use:
bc -l <<< '100/3' # saves a few hits
33.33333333333333333333
bash
As noted by others, bash does not support floating point arithmetic, although you could fake it with some fixed decimal trickery, e.g. with two decimals:
echo $(( 100 * 1 / 3 )) | sed -e 's/..$/.&/;t' -e 's/.$/.0&/'
Output:
.33
See Nilfred's answer for a similar but more concise approach.
Alternatives
Besides the mentioned bc and awk alternatives there are also the following:
clisp
clisp -x '(/ 1.0 3)'
with cleaned up output:
clisp --quiet -x '(/ 1.0 3)'
or through stdin:
echo '(/ 1.0 3)' | clisp --quiet | tail -n1
dc
echo 2k 1 3 /p | dc
genius cli calculator
echo 1/3.0 | genius
ghostscript
echo 1 3 div = | gs -dNODISPLAY -dQUIET | sed -n '1s/.*>//p'
gnuplot
echo 'pr 1/3.' | gnuplot
Imagemagick
convert xc: -format '%[fx:1/3]' info:
or through stdin:
echo 1/3 | { convert xc: -format "%[fx:$(cat)]" info:; }
jq
jq -n 1/3
or through stdin:
echo 1/3 | jq -nf /dev/stdin
ksh
echo 'print $(( 1/3. ))' | ksh
lua
lua -e 'print(1/3)'
or through stdin:
echo 'print(1/3)' | lua
maxima
echo '1/3,numer;' | maxima
with cleaned up output:
echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'
node
echo 1/3 | node -p
octave
echo 1/3 | octave
perl
echo print 1/3 | perl
python2
echo print 1/3. | python2
python3
echo 'print(1/3)' | python3
R
echo 1/3 | R --no-save
with cleaned up output:
echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'
ruby
echo puts 1/3.0 | ruby
units
units 1/3
with compact output:
units --com 1/3
wcalc
echo 1/3 | wcalc
with cleaned up output:
echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2
zsh
print $(( 1/3. ))
or through stdin:
echo 'print $(( 1/3. ))' | zsh
Other sources
Stéphane Chazelas answered a similar question over on UL.
Improving a little the answer of marvin:
RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")
bc doesn't come always as installed package.
You could use bc by the -l option (the L letter)
RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)
As an alternative to bc, you can use awk within your script.
For example:
echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'
In the above, " %.2f " tells the printf function to return a floating point number with two digits after the decimal place. I used echo to pipe in the variables as fields since awk operates properly on them. " $1 " and " $2 " refer to the first and second fields input into awk.
And you can store the result as some other variable using:
RESULT = `echo ...`
Well, before float was a time where fixed decimals logic was used:
IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33
Last line is a bashim, if not using bash, try this code instead:
IMG_WIDTH=100
IMG2_WIDTH=3
INTEGER=$(($IMG_WIDTH/$IMG2_WIDTH))
DECIMAL=$(tail -c 3 <<< $((${IMG_WIDTH}00/$IMG2_WIDTH)))
RESULT=$INTEGER.$DECIMAL
echo $RESULT
33.33
The rationale behind the code is: multiply by 100 before divide to get 2 decimals.
It's perfect time to try zsh, an (almost) bash superset, with many additional nice features including floating point math. Here is what your example would be like in zsh:
% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875
This post may help you: bash - Worth switching to zsh for casual use?
If you found the variant of your preference you can also wrap it into a function.
Here I'm wrapping some bashism into a div function:
One liner:
function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}
Or multi line:
function div {
local _d=${3:-2}
local _n=0000000000
_n=${_n:0:$_d}
local _r=$(($1$_n/$2))
_r=${_r:0:-$_d}.${_r: -$_d}
echo $_r
}
Now you have the function
div <dividend> <divisor> [<precision=2>]
and use it like
> div 1 2
.50
> div 273 123 5
2.21951
> x=$(div 22 7)
> echo $x
3.14
UPDATE
I added a little script which provides you the basic operations with floating point numbers for bash:
Usage:
> add 1.2 3.45
4.65
> sub 1000 .007
999.993
> mul 1.1 7.07
7.7770
> div 10 3
3.
> div 10 3.000
3.333
And here the script:
#!/bin/bash
__op() {
local z=00000000000000000000000000000000
local a1=${1%.*}
local x1=${1//./}
local n1=$((${#x1}-${#a1}))
local a2=${2%.*}
local x2=${2//./}
local n2=$((${#x2}-${#a2}))
local n=$n1
if (($n1 < $n2)); then
local n=$n2
x1=$x1${z:0:$(($n2-$n1))}
fi
if (($n1 > $n2)); then
x2=$x2${z:0:$(($n1-$n2))}
fi
if [ "$3" == "/" ]; then
x1=$x1${z:0:$n}
fi
local r=$(($x1"$3"$x2))
local l=$((${#r}-$n))
if [ "$3" == "*" ]; then
l=$(($l-$n))
fi
echo ${r:0:$l}.${r:$l}
}
add() { __op $1 $2 + ;}
sub() { __op $1 $2 - ;}
mul() { __op $1 $2 "*" ;}
div() { __op $1 $2 / ;}
How to do floating point calculations in bash:
Instead of using "here strings" (<<<) with the bc command, like one of the most-upvoted examples does, here's my favorite bc floating point example, right from the EXAMPLES section of the bc man pages (see man bc for the manual pages).
Before we begin, know that an equation for pi is: pi = 4*atan(1). a() below is the bc math function for atan().
This is how to store the result of a floating point calculation into a bash variable--in this case into a variable called pi. Note that scale=10 sets the number of decimal digits of precision to 10 in this case. Any decimal digits after this place are truncated.
pi=$(echo "scale=10; 4*a(1)" | bc -l)
Now, to have a single line of code that also prints out the value of this variable, simply add the echo command to the end as a follow-up command, as follows. Note the truncation at 10 decimal places, as commanded:
pi=$(echo "scale=10; 4*a(1)" | bc -l); echo $pi
3.1415926532
Finally, let's throw in some rounding. Here we will use the printf function to round to 4 decimal places. Note that the 3.14159... rounds now to 3.1416. Since we are rounding, we no longer need to use scale=10 to truncate to 10 decimal places, so we'll just remove that part. Here's the end solution:
pi=$(printf %.4f $(echo "4*a(1)" | bc -l)); echo $pi
3.1416
Here's another really great application and demo of the above techniques: measuring and printing run-time.
(See also my other answer here).
Note that dt_min gets rounded from 0.01666666666... to 0.017:
start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); echo "dt_sec = $dt_sec; dt_min = $dt_min"
dt_sec = 1; dt_min = 0.017
Related:
[my answer] https://unix.stackexchange.com/questions/52313/how-to-get-execution-time-of-a-script-effectively/547849#547849
[my question] What do three left angle brackets (`<<<`) mean in bash?
https://unix.stackexchange.com/questions/80362/what-does-mean/80368#80368
https://askubuntu.com/questions/179898/how-to-round-decimals-using-bc-in-bash/574474#574474
While you can't use floating point division in Bash you can use fixed point division. All that you need to do is multiply your integers by a power of 10 and then divide off the integer part and use a modulo operation to get the fractional part. Rounding as needed.
#!/bin/bash
n=$1
d=$2
# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))
I know it's old, but too tempting. So, the answer is: you can't... but you kind of can. let's try this:
$IMG_WIDTH=1024
$IMG2_WIDTH=2048
$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))"
Like that, you get 2 digits after the point, truncated (call it rounding to the lower) in pure bash (no need to launch other processes). Of course, if you only need one digit after the point you multiply by 10 and do modulo 10.
What this does:
first $((...)) does integer division;
second $((...)) does integer division on something 100 times larger, essentially moving your 2 digits to the left of the point, then (%) getting you only those 2 digits by doing modulo.
Bonus track: bc version × 1000 took 1.8 seconds on my laptop, while the pure bash one took 0.016 seconds.
It's not really floating point, but if you want something that sets more than one result in one invocation of bc...
source /dev/stdin <<<$(bc <<< '
d='$1'*3.1415926535897932384626433832795*2
print "d=",d,"\n"
a='$1'*'$1'*3.1415926535897932384626433832795
print "a=",a,"\n"
')
echo bc radius:$1 area:$a diameter:$d
computes the area and diameter of a circle whose radius is given in $1
There are scenarios in wich you cannot use bc becouse it might simply not be present, like in some cut down versions of busybox or embedded systems. In any case limiting outer dependencies is always a good thing to do so you can always add zeroes to the number being divided by (numerator), that is the same as multiplying by a power of 10 (you should choose a power of 10 according to the precision you need), that will make the division output an integer number. Once you have that integer treat it as a string and position the decimal point (moving it from right to left) a number of times equal to the power of ten you multiplied the numerator by. This is a simple way of obtaining float results by using only integer numbers.
For those trying to calculate percentages with the accepted answer, but are losing precision:
If you run this:
echo "scale=2; (100/180) * 180" | bc
You get 99.00 only, which is losing precision.
If you run it this way:
echo "result = (100/180) * 180; scale=2; result / 1" | bc -l
Now you get 99.99.
Because you're scaling only at the moment of printing.
Refer to here
Use calc. It's the easiest I found
example:
calc 1+1
2
calc 1/10
0.1
As others have indicated, bash does not have built-in floating-point operators.
You can implement floating-point in bash, even without using calculator programs like bc and awk, or any external programs for that matter.
I'm doing exactly this in my project, shellmath, in three basic steps:
Break the numbers down into their integer and fractional parts
Use the built-in integer operators to process the parts separately while being careful about place-value and carrying
Recombine the results
As a teaser, I've added a demo script that calculates e using its Taylor series centered at x=0.
Please check it out if you have a moment. I welcome your feedback!
** Injection-safe floating point math in bash/shell **
Note: The focus of this answer is provide ideas for injection-safe solution to performing math in bash (or other shells). Of course, same can be used, with minor adjustment to perform advanced string processing, etc.
Most of the solution that were by presented, construct small scriptlet on the fly, using external data (variables, files, command line, environment variables). The external input can be used to inject malicious code into the engine, many of them
Below is a comparison on using the various language to perform basic math calculation, where the result in floating point. It calculates A + B * 0.1 (as floating point).
All solution attempt avoid creating dynamic scriptlets, which are extremely hard to maintain, Instead they use static program, and pass parameters into designated variable. They will safely handle parameters with special characters - reducing the possibility of code injection. The exception is 'BC' which does not provide input/output facility
The exception is 'bc', which does not provide any input/output, all the data comes via programs in stdin, and all output goes to stdout. All calculation are executing in a sandbox, which does not allow side effect (opening files, etc.). In theory, injection safe by design!
A=5.2
B=4.3
# Awk: Map variable into awk
# Exit 0 (or just exit) for success, non-zero for error.
#
awk -v A="$A" -v B="$B" 'BEGIN { print A + B * 0.1 ; exit 0}'
# Perl
perl -e '($A,$B) = #ARGV ; print $A + $B * 0.1' "$A" "$B"
# Python 2
python -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print a+b*0.1' "$A" "$B"
# Python 3
python3 -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print(a+b*0.1)' "$A" "$B"
# BC
bc <<< "scale=1 ; $A + $B * 0.1"
Bash can calculate floating point results just fine without any other programs.
Bash independently even can calculate π to the ninth decimal place accurately.
Example:
calc=104348/33215
accuracy=9
calc99p9=$((10**$accuracy))*$calc
result99p9=$((calc99p9))
result=${result99p9: -${#result99p9}: -$accuracy}.${result99p9: -$accuracy}
echo Bash calculated pi to be $result
results in
Bash calculated pi to be 3.141592653
Dividend = Divisor × Quotient + Remainder
Lets just calculate the quotient and remainder.
As well as concatenate those strings in a variable.
New way valid only to log_decimal divisors:
function main() {
bar=10030
divisor=100
# divisor=50
quotient=$((bar / divisor))
# remainder=$((bar - v_int * divisor))
remainder=$((bar % divisor))
remainder_init=$remainder
printf "%-15s --> %s\n" "quotient" "$quotient"
printf "%-15s --> %s\n" "remainder" "$remainder"
cnt=0
while :; do
remainder=$((remainder * 10))
aux=$((remainder / divisor))
printf "%-15s --> %s\n" "aux" "$aux"
[[ aux -ne 0 ]] && break
((cnt += 1))
printf "%-15s --> %s\n" "remainder" "$remainder"
done
printf "%-15s --> %s\n" "cnt" "$cnt"
printf "%-15s --> %s\n" "aux" "$aux"
printf $quotient
printf "."
for i in $(seq 1 $cnt); do printf "0"; done
printf $remainder_init
}
clear
main
Old wrong way:
bar=1234 \
&& divisor=1000 \
&& foo=$(printf "%s.%s" $(( bar / divisor )) $(( bar % divisor ))) \
&& printf "bar is %d miliseconds or %s seconds\n" $bar $foo
Output: bar is 1234 miliseconds or 1.234 seconds
here is awk command: -F = field separator == +
echo "2.1+3.1" | awk -F "+" '{print ($1+$2)}'
how precise do you need the output to be ? if an approximation via binning is already acceptable for your use case, you can even go one step further and take advantage of POSIX exit codes [0:256) (all other integers mod'd back to that range).
eg : in gawk/nawk/mawk-1, it already gives me epoch seconds down to the integer level, but I wanted to expand that to extract near-milliseconds precision but not overly pedantic about it, i run this command in a POSIX shell
exit $(( 10#` gdate +%5N ` * 256 / 100000 ))
directly assigning a 5-digit integer representing 0.xxxxxx output of gnu-date into 1 of 256 bins, then un-doing that 256 once awk obtains the exit code of the system() call, i.e. the selected bin #. I found this approach to have lower overhead than using a full getline call.
This method also directly captures the output into the POSIX exit code instead of also having an extra terminal print out.
(the shell arithmetic auto floors it to integer if written this way instead of * 0.0256). Putting together into an awk function, it would resemble this. The 10# is to force base-10 to prevent posix shell interpreting "01733" as an octal number.
function msecs() { # n x 2**-8 = n divided by 256
return 2^-8 * \
system( "exit \44\50\50 " \
" 10\43\140 gdate \53" \
"%5N\140 \52 " \
"256 \57 100000 \51\51" )
}
for my own code, i apply another 0.6% haircut to account for shell-overhead.
Let us take an example to undertsand, if u want to find average of n array elements (Ofcourse the average will be in float/decimals)
declare -a arr
echo "How many numbers you want to enter?"
read n
echo "Enter the Array Elements"
for(( i=0 ; i<$n ; i++))
do
read array_elements
arr[$i]="$array_elements"
done
sum=0
for i in "${arr[#]}"
do
#sum and avg
sum=$(($sum + $i))
#average will come in decimals
avg=`echo $sum / $n | bc -l`
done
# Output results:
printf "Average of Array Elements %.2f:" $avg
So we will use "| bc -l" to do floating calculations

BASH: Calculating given operations [duplicate]

I am trying to divide two image widths in a Bash script, but bash gives me 0 as the result:
RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))
I did study the Bash guide and I know I should use bc, in all examples in internet they use bc. In echo I tried to put the same thing in my SCALE but it didn't work.
Here is the example I found in the tutorials:
echo "scale=2; ${userinput}" | bc
How can I get Bash to give me a float like 0.5?
You can't. bash only does integers; you must delegate to a tool such as bc.
you can do this:
bc <<< 'scale=2; 100/3'
33.33
UPDATE 20130926 : you can use:
bc -l <<< '100/3' # saves a few hits
33.33333333333333333333
bash
As noted by others, bash does not support floating point arithmetic, although you could fake it with some fixed decimal trickery, e.g. with two decimals:
echo $(( 100 * 1 / 3 )) | sed -e 's/..$/.&/;t' -e 's/.$/.0&/'
Output:
.33
See Nilfred's answer for a similar but more concise approach.
Alternatives
Besides the mentioned bc and awk alternatives there are also the following:
clisp
clisp -x '(/ 1.0 3)'
with cleaned up output:
clisp --quiet -x '(/ 1.0 3)'
or through stdin:
echo '(/ 1.0 3)' | clisp --quiet | tail -n1
dc
echo 2k 1 3 /p | dc
genius cli calculator
echo 1/3.0 | genius
ghostscript
echo 1 3 div = | gs -dNODISPLAY -dQUIET | sed -n '1s/.*>//p'
gnuplot
echo 'pr 1/3.' | gnuplot
Imagemagick
convert xc: -format '%[fx:1/3]' info:
or through stdin:
echo 1/3 | { convert xc: -format "%[fx:$(cat)]" info:; }
jq
jq -n 1/3
or through stdin:
echo 1/3 | jq -nf /dev/stdin
ksh
echo 'print $(( 1/3. ))' | ksh
lua
lua -e 'print(1/3)'
or through stdin:
echo 'print(1/3)' | lua
maxima
echo '1/3,numer;' | maxima
with cleaned up output:
echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'
node
echo 1/3 | node -p
octave
echo 1/3 | octave
perl
echo print 1/3 | perl
python2
echo print 1/3. | python2
python3
echo 'print(1/3)' | python3
R
echo 1/3 | R --no-save
with cleaned up output:
echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'
ruby
echo puts 1/3.0 | ruby
units
units 1/3
with compact output:
units --com 1/3
wcalc
echo 1/3 | wcalc
with cleaned up output:
echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2
zsh
print $(( 1/3. ))
or through stdin:
echo 'print $(( 1/3. ))' | zsh
Other sources
Stéphane Chazelas answered a similar question over on UL.
Improving a little the answer of marvin:
RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")
bc doesn't come always as installed package.
You could use bc by the -l option (the L letter)
RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)
As an alternative to bc, you can use awk within your script.
For example:
echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'
In the above, " %.2f " tells the printf function to return a floating point number with two digits after the decimal place. I used echo to pipe in the variables as fields since awk operates properly on them. " $1 " and " $2 " refer to the first and second fields input into awk.
And you can store the result as some other variable using:
RESULT = `echo ...`
Well, before float was a time where fixed decimals logic was used:
IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33
Last line is a bashim, if not using bash, try this code instead:
IMG_WIDTH=100
IMG2_WIDTH=3
INTEGER=$(($IMG_WIDTH/$IMG2_WIDTH))
DECIMAL=$(tail -c 3 <<< $((${IMG_WIDTH}00/$IMG2_WIDTH)))
RESULT=$INTEGER.$DECIMAL
echo $RESULT
33.33
The rationale behind the code is: multiply by 100 before divide to get 2 decimals.
It's perfect time to try zsh, an (almost) bash superset, with many additional nice features including floating point math. Here is what your example would be like in zsh:
% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875
This post may help you: bash - Worth switching to zsh for casual use?
If you found the variant of your preference you can also wrap it into a function.
Here I'm wrapping some bashism into a div function:
One liner:
function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}
Or multi line:
function div {
local _d=${3:-2}
local _n=0000000000
_n=${_n:0:$_d}
local _r=$(($1$_n/$2))
_r=${_r:0:-$_d}.${_r: -$_d}
echo $_r
}
Now you have the function
div <dividend> <divisor> [<precision=2>]
and use it like
> div 1 2
.50
> div 273 123 5
2.21951
> x=$(div 22 7)
> echo $x
3.14
UPDATE
I added a little script which provides you the basic operations with floating point numbers for bash:
Usage:
> add 1.2 3.45
4.65
> sub 1000 .007
999.993
> mul 1.1 7.07
7.7770
> div 10 3
3.
> div 10 3.000
3.333
And here the script:
#!/bin/bash
__op() {
local z=00000000000000000000000000000000
local a1=${1%.*}
local x1=${1//./}
local n1=$((${#x1}-${#a1}))
local a2=${2%.*}
local x2=${2//./}
local n2=$((${#x2}-${#a2}))
local n=$n1
if (($n1 < $n2)); then
local n=$n2
x1=$x1${z:0:$(($n2-$n1))}
fi
if (($n1 > $n2)); then
x2=$x2${z:0:$(($n1-$n2))}
fi
if [ "$3" == "/" ]; then
x1=$x1${z:0:$n}
fi
local r=$(($x1"$3"$x2))
local l=$((${#r}-$n))
if [ "$3" == "*" ]; then
l=$(($l-$n))
fi
echo ${r:0:$l}.${r:$l}
}
add() { __op $1 $2 + ;}
sub() { __op $1 $2 - ;}
mul() { __op $1 $2 "*" ;}
div() { __op $1 $2 / ;}
How to do floating point calculations in bash:
Instead of using "here strings" (<<<) with the bc command, like one of the most-upvoted examples does, here's my favorite bc floating point example, right from the EXAMPLES section of the bc man pages (see man bc for the manual pages).
Before we begin, know that an equation for pi is: pi = 4*atan(1). a() below is the bc math function for atan().
This is how to store the result of a floating point calculation into a bash variable--in this case into a variable called pi. Note that scale=10 sets the number of decimal digits of precision to 10 in this case. Any decimal digits after this place are truncated.
pi=$(echo "scale=10; 4*a(1)" | bc -l)
Now, to have a single line of code that also prints out the value of this variable, simply add the echo command to the end as a follow-up command, as follows. Note the truncation at 10 decimal places, as commanded:
pi=$(echo "scale=10; 4*a(1)" | bc -l); echo $pi
3.1415926532
Finally, let's throw in some rounding. Here we will use the printf function to round to 4 decimal places. Note that the 3.14159... rounds now to 3.1416. Since we are rounding, we no longer need to use scale=10 to truncate to 10 decimal places, so we'll just remove that part. Here's the end solution:
pi=$(printf %.4f $(echo "4*a(1)" | bc -l)); echo $pi
3.1416
Here's another really great application and demo of the above techniques: measuring and printing run-time.
(See also my other answer here).
Note that dt_min gets rounded from 0.01666666666... to 0.017:
start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); echo "dt_sec = $dt_sec; dt_min = $dt_min"
dt_sec = 1; dt_min = 0.017
Related:
[my answer] https://unix.stackexchange.com/questions/52313/how-to-get-execution-time-of-a-script-effectively/547849#547849
[my question] What do three left angle brackets (`<<<`) mean in bash?
https://unix.stackexchange.com/questions/80362/what-does-mean/80368#80368
https://askubuntu.com/questions/179898/how-to-round-decimals-using-bc-in-bash/574474#574474
While you can't use floating point division in Bash you can use fixed point division. All that you need to do is multiply your integers by a power of 10 and then divide off the integer part and use a modulo operation to get the fractional part. Rounding as needed.
#!/bin/bash
n=$1
d=$2
# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))
I know it's old, but too tempting. So, the answer is: you can't... but you kind of can. let's try this:
$IMG_WIDTH=1024
$IMG2_WIDTH=2048
$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))"
Like that, you get 2 digits after the point, truncated (call it rounding to the lower) in pure bash (no need to launch other processes). Of course, if you only need one digit after the point you multiply by 10 and do modulo 10.
What this does:
first $((...)) does integer division;
second $((...)) does integer division on something 100 times larger, essentially moving your 2 digits to the left of the point, then (%) getting you only those 2 digits by doing modulo.
Bonus track: bc version × 1000 took 1.8 seconds on my laptop, while the pure bash one took 0.016 seconds.
It's not really floating point, but if you want something that sets more than one result in one invocation of bc...
source /dev/stdin <<<$(bc <<< '
d='$1'*3.1415926535897932384626433832795*2
print "d=",d,"\n"
a='$1'*'$1'*3.1415926535897932384626433832795
print "a=",a,"\n"
')
echo bc radius:$1 area:$a diameter:$d
computes the area and diameter of a circle whose radius is given in $1
There are scenarios in wich you cannot use bc becouse it might simply not be present, like in some cut down versions of busybox or embedded systems. In any case limiting outer dependencies is always a good thing to do so you can always add zeroes to the number being divided by (numerator), that is the same as multiplying by a power of 10 (you should choose a power of 10 according to the precision you need), that will make the division output an integer number. Once you have that integer treat it as a string and position the decimal point (moving it from right to left) a number of times equal to the power of ten you multiplied the numerator by. This is a simple way of obtaining float results by using only integer numbers.
For those trying to calculate percentages with the accepted answer, but are losing precision:
If you run this:
echo "scale=2; (100/180) * 180" | bc
You get 99.00 only, which is losing precision.
If you run it this way:
echo "result = (100/180) * 180; scale=2; result / 1" | bc -l
Now you get 99.99.
Because you're scaling only at the moment of printing.
Refer to here
Use calc. It's the easiest I found
example:
calc 1+1
2
calc 1/10
0.1
As others have indicated, bash does not have built-in floating-point operators.
You can implement floating-point in bash, even without using calculator programs like bc and awk, or any external programs for that matter.
I'm doing exactly this in my project, shellmath, in three basic steps:
Break the numbers down into their integer and fractional parts
Use the built-in integer operators to process the parts separately while being careful about place-value and carrying
Recombine the results
As a teaser, I've added a demo script that calculates e using its Taylor series centered at x=0.
Please check it out if you have a moment. I welcome your feedback!
** Injection-safe floating point math in bash/shell **
Note: The focus of this answer is provide ideas for injection-safe solution to performing math in bash (or other shells). Of course, same can be used, with minor adjustment to perform advanced string processing, etc.
Most of the solution that were by presented, construct small scriptlet on the fly, using external data (variables, files, command line, environment variables). The external input can be used to inject malicious code into the engine, many of them
Below is a comparison on using the various language to perform basic math calculation, where the result in floating point. It calculates A + B * 0.1 (as floating point).
All solution attempt avoid creating dynamic scriptlets, which are extremely hard to maintain, Instead they use static program, and pass parameters into designated variable. They will safely handle parameters with special characters - reducing the possibility of code injection. The exception is 'BC' which does not provide input/output facility
The exception is 'bc', which does not provide any input/output, all the data comes via programs in stdin, and all output goes to stdout. All calculation are executing in a sandbox, which does not allow side effect (opening files, etc.). In theory, injection safe by design!
A=5.2
B=4.3
# Awk: Map variable into awk
# Exit 0 (or just exit) for success, non-zero for error.
#
awk -v A="$A" -v B="$B" 'BEGIN { print A + B * 0.1 ; exit 0}'
# Perl
perl -e '($A,$B) = #ARGV ; print $A + $B * 0.1' "$A" "$B"
# Python 2
python -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print a+b*0.1' "$A" "$B"
# Python 3
python3 -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print(a+b*0.1)' "$A" "$B"
# BC
bc <<< "scale=1 ; $A + $B * 0.1"
Bash can calculate floating point results just fine without any other programs.
Bash independently even can calculate π to the ninth decimal place accurately.
Example:
calc=104348/33215
accuracy=9
calc99p9=$((10**$accuracy))*$calc
result99p9=$((calc99p9))
result=${result99p9: -${#result99p9}: -$accuracy}.${result99p9: -$accuracy}
echo Bash calculated pi to be $result
results in
Bash calculated pi to be 3.141592653
Dividend = Divisor × Quotient + Remainder
Lets just calculate the quotient and remainder.
As well as concatenate those strings in a variable.
New way valid only to log_decimal divisors:
function main() {
bar=10030
divisor=100
# divisor=50
quotient=$((bar / divisor))
# remainder=$((bar - v_int * divisor))
remainder=$((bar % divisor))
remainder_init=$remainder
printf "%-15s --> %s\n" "quotient" "$quotient"
printf "%-15s --> %s\n" "remainder" "$remainder"
cnt=0
while :; do
remainder=$((remainder * 10))
aux=$((remainder / divisor))
printf "%-15s --> %s\n" "aux" "$aux"
[[ aux -ne 0 ]] && break
((cnt += 1))
printf "%-15s --> %s\n" "remainder" "$remainder"
done
printf "%-15s --> %s\n" "cnt" "$cnt"
printf "%-15s --> %s\n" "aux" "$aux"
printf $quotient
printf "."
for i in $(seq 1 $cnt); do printf "0"; done
printf $remainder_init
}
clear
main
Old wrong way:
bar=1234 \
&& divisor=1000 \
&& foo=$(printf "%s.%s" $(( bar / divisor )) $(( bar % divisor ))) \
&& printf "bar is %d miliseconds or %s seconds\n" $bar $foo
Output: bar is 1234 miliseconds or 1.234 seconds
here is awk command: -F = field separator == +
echo "2.1+3.1" | awk -F "+" '{print ($1+$2)}'
how precise do you need the output to be ? if an approximation via binning is already acceptable for your use case, you can even go one step further and take advantage of POSIX exit codes [0:256) (all other integers mod'd back to that range).
eg : in gawk/nawk/mawk-1, it already gives me epoch seconds down to the integer level, but I wanted to expand that to extract near-milliseconds precision but not overly pedantic about it, i run this command in a POSIX shell
exit $(( 10#` gdate +%5N ` * 256 / 100000 ))
directly assigning a 5-digit integer representing 0.xxxxxx output of gnu-date into 1 of 256 bins, then un-doing that 256 once awk obtains the exit code of the system() call, i.e. the selected bin #. I found this approach to have lower overhead than using a full getline call.
This method also directly captures the output into the POSIX exit code instead of also having an extra terminal print out.
(the shell arithmetic auto floors it to integer if written this way instead of * 0.0256). Putting together into an awk function, it would resemble this. The 10# is to force base-10 to prevent posix shell interpreting "01733" as an octal number.
function msecs() { # n x 2**-8 = n divided by 256
return 2^-8 * \
system( "exit \44\50\50 " \
" 10\43\140 gdate \53" \
"%5N\140 \52 " \
"256 \57 100000 \51\51" )
}
for my own code, i apply another 0.6% haircut to account for shell-overhead.
Let us take an example to undertsand, if u want to find average of n array elements (Ofcourse the average will be in float/decimals)
declare -a arr
echo "How many numbers you want to enter?"
read n
echo "Enter the Array Elements"
for(( i=0 ; i<$n ; i++))
do
read array_elements
arr[$i]="$array_elements"
done
sum=0
for i in "${arr[#]}"
do
#sum and avg
sum=$(($sum + $i))
#average will come in decimals
avg=`echo $sum / $n | bc -l`
done
# Output results:
printf "Average of Array Elements %.2f:" $avg
So we will use "| bc -l" to do floating calculations

Resources