Bash how to store a division to a variable - bash

I am trying to calculate below formula and store the value to a variable.
The pseudo code should look like:
a=10
b=5
c=$(((($a-$b)/52)) | bc -l)
echo $c
The result is empty. I couldn't figure out the syntax using bc. Please help me use bc instead of awk or other method.

There are two things you need to be aware of. The first is that bc uses standard input for expressions so you would need to actually pipe your expression through it, or use the <<< redirection operator, one of:
c=$(echo "($a - $b) / 52" | bc)
c=$(bc <<< "($a - $b) / 52")
The <<< method is specific to bash and ksh (an possibly others, but I'm not really au fait with them). The other method can be used in most shells.
Secondly, you should be careful when using big numbers for this since bc has the annoying habit of splitting them across lines:
pax$ x=999999999999999999999999999999999999999999999999999999999999999999999
pax$ echo "$x / 7" | bc
14285714285714285714285714285714285714285714285714285714285714285714\
2
In order to avoid this, you need to change the line length:
pax$ echo "$x / 7" | BC_LINE_LENGTH=0 bc
142857142857142857142857142857142857142857142857142857142857142857142

You can use this:
a=10
b=5
c=$(bc -l <<< "($a-$b)/52")
echo "$c"
.09615384615384615384
Or by setting a scale of 3:
c=$(bc -l <<< "scale=3; ($a-$b)/52")
echo "$c"
.096

Related

How to calculate extra large numbers with bc in bash

I have a file with 1800 lines that look like this
600.76
600.66
700.44
566.66
Ect..
I made a bash script to calculate the mean.
Now I first made a variable to count the total column lines like:
Lines="$(awk 'END{print NR}' file.txt)"
Then another variable for the sum of that column like this:
Sum="$(awk '{s+1=$1}END {print s}' file.txt)"
Lastly I'm finding the mean like this:
Echo "scale=2 ; $Sum / $Lines" | bc
With debugging enabled It returns:
+echo 'scale=2 ; 1.72161e+06 / 1800'
(Standard_1): syntax error
I realize now bc doesn't do scientific notation but how do I get around this.
I'm OK with short handing the decimal by restricting it to 2 or 3 places.
Unnecessary to use awk. Simple oneliner can do the job.
echo "scale=2; ("$(paste -sd+ file.txt)")"/$(wc -l <file.txt)|bc
Use bc -l for both summation and final division:
sum=0
count=0
while read number; do
number=$(printf "%f\n" $number) # get rid of scientific notation
sum=$(echo "$sum" '+' "$number" | bc -l)
count=$((count + 1))
done < input
avg=$(echo $sum / $count | bc -l)
echo $avg

How to display number to two decimal places, even zero .00 using BC or DC [duplicate]

Greetings!
I uses bс to make some calculations in my script. For example:
bc
scale=6
1/2
.500000
For further usage in my script I need "0.500000" insted of ".500000".
Could you help me please to configure bc output number format for my case?
In one line:
printf "%0.6f\n" $(bc -q <<< scale=6\;1/2)
Just do all your calculations and output in awk:
float_scale=6
result=$(awk -v scale=$floatscale 'BEGIN { printf "%.*f\n", scale, 1/2 }')
As an alternative, if you'd prefer to use bc and not use AWK alone or with 'bc', Bash's printf supports floating point numbers even though the rest of Bash doesn't.
result=$(echo "scale=$float_scale; $*" | bc -q 2>/dev/null)
result=$(printf '%*.*f' 0 "$float_scale" "$result")
The second line above could instead be:
printf -v $result '%*.*f' 0 "$float_scale" "$result"
Which works kind of like sprintf would and doesn't create a subshell.
Quick and dirty, since scale only applies to the decimal digits and bc does not seem to have a sprintf-like function:
$ bc
scale = 6
result = 1 / 2
if (0 <= result && result < 1) {
print "0"
}
print result;
echo "scale=3;12/7" | bc -q | sed 's/^\\./0./;s/0*$//;s/\\.$//'
I believe here is modified version of the function:
float_scale=6
function float_eval()
{
local stat=0
local result=0.0
if [[ $# -gt 0 ]]; then
result=$(echo "scale=$float_scale; $*" | bc -q | awk '{printf "%f\n", $0}' 2>/dev/null)
stat=$?
if [[ $stat -eq 0 && -z "$result" ]]; then stat=1; fi
fi
echo $result
return $stat
}
Can you put the bc usage into a little better context? What are you using the results of bc for?
Given the following in a file called some_math.bc
scale=6
output=1/2
print output
on the command line I can do the following to add a zero:
$ bc -q some_math.bc | awk '{printf "%08f\n", $0}'
0.500000
If I only needed the output string to have a zero for formatting purposes, I'd use awk.

How to add an integer number and a float number in a bash shell script

I have two numbers:
value1=686
value2=228.35
I am not able to add an integer and a float. Please help me out to get the result.
I am running it in bash.
echo 1 + 3.5 | bc
awk "BEGIN {print 1+3.5; exit}"
python -c "print 1+3.5"
perl -e "print 1+3.5"
Just replace the numbers with your variables, eg: echo $n1 + $n2 | bc
If you have the bc language installed, you can do the following:
#!bin/bash
numone=1.234
numtwo=0.124
total=`echo $numone + $numtwo | bc`
echo $total
If you don't have bc, then you can try with awk. Just in one single line:
echo 1.234 2.345 | awk '{print $1 + $2}'
There are plenty of other options, also. Like python, perl, php....
Bash doesn't have floating-point types, but you can use a calculator such as bc:
a=686
b=228.35
c=`echo $a + $b | bc`
echo "$c"
#!/bin/Bash
echo "Enter the two numbers to be added:"
read n1
read n2
answer=$(($n1+$n2))
echo $answer

Bash escaping and syntax

I have a small bash file which I intend to use to determine my current ping vs my average ping.
#!/bin/bash
output=($(ping -qc 1 google.com | tail -n 1))
echo "`cut -d/ -f1 <<< "${output[3]}"`-20" | bc
This outputs my ping - 20 ms, which is the number I want. However, I also want to prepend a + if the number is positive and append "ms".
This brings me to my overarching problem: Bash syntax regarding escaping and such heavy "indenting" is kind of flaky.
While I'll be satisfied with an answer of how to do what I wanted, I'd like a link to, or explanation of how exactly bash syntax works dealing with this sort of thing.
output=($(ping -qc 1 google.com | tail -n 1))
echo "${output[3]}" | awk -F/ '{printf "%+fms\n", $1-20}'
The + modifier in printf tells it to print the sign, whether it's positive or negative.
And since we're using awk, there's no need to use cut or bc to get a field or do arithmetic.
Escaping is pretty awful in bash if you use the deprecated `..` style command expansion. In this case, you have to escape any backticks, which means you also have to escape any other escapes. $(..) nests a lot better, since it doesn't add another layer of escaping.
In any case, I'd just do it directly:
ping -qc 1 google.com.org | awk -F'[=/ ]+' '{n=$6}
END { v=(n-20); if(v>0) printf("+"); print v}'
Here's my take on it, recognizing that the result from bc can be treated as a string:
output=($(ping -qc 1 google.com | tail -n 1))
output=$(echo "`cut -d/ -f1 <<< "${output[3]}"`-20" | bc)' ms'
[[ "$output" != -* ]] && output="+$output"
echo "$output"
Bash cannot handle floating point numbers. A workaround is to use awk like this:
#!/bin/bash
output=($(ping -qc 1 google.com | tail -n 1))
echo "`cut -d/ -f1 <<< "${output[3]}"`-20" | bc | awk '{if ($1 >= 0) printf "+%fms\n", $1; else printf "%fms\n", $1}'
Note that this does not print anything if the result of bc is not positive
Output:
$ ./testping.sh
+18.209000ms

How to do exponentiation in Bash

I tried
echo 10**2
which prints 10**2. How to calculate the right result, 100?
You can use the let builtin:
let var=10**2 # sets var to 100.
echo $var # prints 100
or arithmetic expansion:
var=$((10**2)) # sets var to 100.
Arithmetic expansion has the advantage of allowing you to do shell arithmetic and then just use the expression without storing it in a variable:
echo $((10**2)) # prints 100.
For large numbers you might want to use the exponentiation operator of the external command bc as:
bash:$ echo 2^100 | bc
1267650600228229401496703205376
If you want to store the above result in a variable you can use command substitution either via the $() syntax:
var=$(echo 2^100 | bc)
or the older backtick syntax:
var=`echo 2^100 | bc`
Note that command substitution is not the same as arithmetic expansion:
$(( )) # arithmetic expansion
$( ) # command substitution
Various ways:
Bash
echo $((10**2))
Awk
awk 'BEGIN{print 10^2}' # POSIX standard
awk 'BEGIN{print 10**2}' # GNU awk extension
bc
echo '10 ^ 2' | bc
dc
dc -e '10 2 ^ p'
Actually var=$((echo 2^100 | bc)) doesn't work - bash is trying to do math inside (()). But a
command line sequence is there instead so it creates an error
var=$(echo 2^100 | bc) works as the value is the result of the command line executing inside
()

Resources