I'm using a serial terminal to provide input into our lab experiment. I found that using
$ echo "5X5"
just returns a string of "5X5". Is there a command to execute a multiplication operation?
Yes, you can use bash's built-in Arithmetic Expansion $(( )) to do some simple maths
$ echo "$((5 * 5))"
25
Check the Shell Arithmetic section in the Bash Reference Manual for a complete list of operators.
For sake of completeness, as other pointed out, if you need arbitrary precision, bc or dc would be better.
For more advanced and precise math consider using bc(1).
echo "3 * 2.19" | bc -l
6.57
Internal Methods
Bash supports arithmetic expansion with $(( expression )). For example:
$ echo $(( 5 * 5 ))
25
External Methods
A number of utilities provide arithmetic, including bc and expr.
$ echo '5 * 5' | /usr/bin/bc
25
$ /usr/bin/expr 5 \* 5
25
The classical solution is:
expr 5 \* 5
expr will only work with integer operands. Another nice option is:
echo 5 5\*p | dc
dc can be made to work with non-integer operands.
A simple shell function (no sed needed) should do the trick of interpreting '5X5'
$ calc() { bc -l <<< ${*//[xX]/*}; }
$ calc 5X5
25
$ calc 5x5
25
$ calc '5*5'
25
I use this function which uses bc and thus supports floating point calculations:
c () {
local a
(( $# > 0 )) && a="$#" || read -r -p "calc: " a
bc -l <<< "$a"
}
Example:
$ c '5*5'
25
$ c 5/5
1.00000000000000000000
$ c 3.4/7.9
.43037974683544303797
Bash's arithmetic expansion doesn't support floats (but Korn shell and zsh do).
Example:
$ ksh -c 'echo "$((3.0 / 4))"'
0.75
I have a simple script I use for this:
me#mycomputer:~$ cat /usr/local/bin/c
#!/bin/sh
echo "$*" | sed 's/x/\*/g' | bc -l
It changes x to * since * is a special character in the shell. Use it as follows:
c 5x5
c 5-4.2 + 1
c '(5 + 5) * 30' (you still have to use quotes if the expression contains any parentheses).
If you like python and have an option to install a package, you can use this utility that I made.
# install pythonp
python -m pip install pythonp
pythonp "5*5"
25
pythonp "1 / (1+math.exp(0.5))"
0.3775406687981454
# define a custom function and pass it to another higher-order function
pythonp "n=10;functools.reduce(lambda x,y:x*y, range(1,n+1))"
3628800
Related
echo 3+3
How can I evaluate such expressions in Bash, in this case to 6?
echo $(( 3+3 ))
expr is the standard way, but it only handles integers.
bash has a couple of extensions, which only handle integers as well:
$((3+3)) returns 6
((3+3)) used in conditionals, returns 0 for true (non-zero) and 1 for false
let 3+3 same as (( ))
let and (( )) can be used to assign values, e.g.
let a=3+3
((a=3+3))
for floating point you can use bc
echo 3+3 | bc
in shells such as zsh/ksh, you can use floats for maths. If you need more maths power, use tools like bc/awk/dc
eg
var=$(echo "scale=2;3.4+43.1" | bc)
var=$(awk 'BEGIN{print 3.4*43.1}')
looking at what you are trying to do
awk '{printf "%.2f\n",$0/59.5}' ball_dropping_times >bull_velocities
You can make use of the expr command as:
expr 3 + 3
To store the result into a variable you can do:
sum=$(expr 3 + 3)
or
sum=`expr 3 + 3`
Lots of ways - most portable is to use the expr command:
expr 3 + 3
I believe the ((3+3)) method is the most rapid as it's interpreted by the shell rather than an external binary.
time a large loop using all suggested methods for the most efficient.
Solved thanks to Dennis, an example of BC-use:
$ cat calc_velo.sh
#!/bin/bash
for i in `cat ball_dropping_times`
do
echo "scale=20; $i / 59.5" | bc
done > ball_velocities
My understanding of math processing involves floating point processing.
Using bashj (https://sourceforge.net/projects/bashj/) you can call a java method (with floating point processing, cos(), sin(), log(), exp()...) using simply
bashj +eval "3+3"
bashj +eval "3.5*5.5"
or in a bashj script, java calls of this kind:
#!/usr/bin/bashj
EXPR="3.0*6.0"
echo $EXPR "=" u.doubleEval($EXPR)
FUNCTIONX="3*x*x+cos(x)+1"
X=3.0
FX=u.doubleEval($FUNCTIONX,$X)
echo "x="$X " => f(x)=" $FUNCTIONX "=" $FX
Note the interesting speed : ~ 10 msec per call (the answer is provided by a JVM server).
Note also that u.doubleEval(1/2) will provide 0.5 (floating point) instead of 0 (integer)
One use case that might be useful in this regard is, if one of your operand itself is a bash command then try this.
echo $(( `date +%s\`+10 )) or even echo $(( `date +%s\`+(60*60) ))
In my case I was trying to get Unixtime 10 seconds and hour later than current time respectively.
This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Closed 4 years ago.
I am attempting to find the sum of a list of numbers' reciprocals. To illustrate what I am trying to do, here's a basic example:
With the file:
1
2
3
4
I would be trying to find the sum of 1/1, 1/2, 1/3 and 1/4. Is there a simple bash one-liner to do this? (I am new to bash, so explanations would be welcome!)
You could do something like this:
sed 's|^|1/|' file | paste -sd+ | bc -l
sed 's|^|1/|' prepends 1/ to every line
paste -sd+ joins all lines with a plus sign creating an arithmetic expression 1/1+1/2+1/3+1/4
bc -l evaluates that arithmetic expression and outputs the result
If you're looking for an arithmetical progression, you can use this bash one-liner using the bc command
d=0; for c in {1..4}; do d=`echo "$d + 1/$c" | bc -l`; done; echo "$d"
Its output is 1 + 0.5 + 0.3333 + 0.25 =
2.08333333333333333333
It works by
Setting a variable named d to 0
Creating a for loop that counts from 1 to 4
In the for loop it sets the d variable to the new value $d + 1/$c passed to the bc -l command executing the arithmetic
And outputs the value with an echo command
I want to use a string to control a for loop in bash. My first test code produces what I would expect and what I want:
$ aa='1 2 3 4'
$ for ii in $aa; do echo $ii; done
1
2
3
4
I'd like to use something like the following instead. This doesn't give the output I'd like (I can see why it does what it does).
$ aa='1..4'
$ for ii in $aa; do echo $ii; done
1..4
Any suggestions on how I should modify the second example to give the same output as the first?
Thanks in advance for any thoughts. I'm slowly learning bash but still have a lot to learn.
Mike
The notation could be written out as:
for ii in {1..4}; do echo "$ii"; done
but the {1..4} needs to be written out like that, no variables involved, and not as the result of variable substitution. That is brace expansion in the Bash manual, and it happens before string expansions, etc. You'll probably be best off using:
for ii in $(seq 1 4); do echo "$ii"; done
where either the 1 or the 4 or both can be shell variables.
You could use seq command (see man seq).
$ aa='1 4'
$ for ii in $(seq $aa); do echo $ii; done
Bash won't do brace expansion with variables, but you can use eval:
$ aa='1..4'
$ for ii in $(eval echo {$aa}); do echo $ii; done
1
2
3
4
You could also split aa into an array:
IFS=. arr=($aa)
for ((ii=arr[0]; ii<arr[2]; ii++)); do echo $ii; done
Note that IFS can only be a single character, so the .. range places the numbers into indexes 0 and 2.
Note There are certainly more elegant ways of doing this, as Ben Grimm's answer, and this is not pure bash, as uses seq and awk.
One way of achieving this is by calling seq. It would be trivial if you knew the numbers in the string beforehand, so there would be no need to do any conversion, as you could simple do seq 1 4 or seq $a $b for that matter.
I assume, however, that your input is indeed a string in the format you mentioned, that is, 1..4 or 20..100. For this purpose you could convert the string into 2 numbers ans use them as parameters for seq.
One of possibly many ways of achieving this is:
$ `echo "1..4" | sed -e 's/\.\./ /g' | awk '{print "seq", $1, $2}'`
1
2
3
4
Note that this will work the same way for any input in the given format. If desired, sed can be changed by tr with similar results.
$ x="10..15"
$ `echo $x | tr "." " " | awk '{print "seq", $1, $2}'`
10
11
12
13
14
15
I read price from user input. When i multiply the input with int like this
T="$((PRICE*QTY))"|bc; gives
line 272: 12.00: syntax error: invalid arithmetic operator (error token is ".00")
or .50
depending on user input. How do i multiply these two variables and get a total with 2 decimal points?
this works:
PRICE=1.1
QTY=21
RES=$(echo "scale=4; $PRICE*$QTY" | bc)
echo $RES
var=$(echo "scale=2;$PRICE*$QTY" |bc)
You can also use awk
awk -vp=$PRICE -vq=$QTY 'BEGIN{printf "%.2f" ,p * q}'
T="$(echo "$PRICE*$QTY" | bc)"
You can use
mul=0.8
exp=200
texp=awk -vp=$mul -vq=$exp 'BEGIN{printf "%.2f" ,p * q}'
Hope this is going to work.
First, trying to do floating-point arithmetic with bc(1) without using the -l flag is bound to give you some funny answers:
sarnold#haig:~$ bc -q
3.5 * 3.5
12.2
sarnold#haig:~$ bc -q -l
3.5 * 3.5
12.25
Second, the $((...)) is an attempt to do arithmetic in your shell; neither my bash nor dash can handle floating point numbers.
If you want to do the arithmetic in your shell, note printf(1) as well as (probably) your shell's built-in printf function. If you want to do the arithmetic in bc, note the special variable scale.
echo 3+3
How can I evaluate such expressions in Bash, in this case to 6?
echo $(( 3+3 ))
expr is the standard way, but it only handles integers.
bash has a couple of extensions, which only handle integers as well:
$((3+3)) returns 6
((3+3)) used in conditionals, returns 0 for true (non-zero) and 1 for false
let 3+3 same as (( ))
let and (( )) can be used to assign values, e.g.
let a=3+3
((a=3+3))
for floating point you can use bc
echo 3+3 | bc
in shells such as zsh/ksh, you can use floats for maths. If you need more maths power, use tools like bc/awk/dc
eg
var=$(echo "scale=2;3.4+43.1" | bc)
var=$(awk 'BEGIN{print 3.4*43.1}')
looking at what you are trying to do
awk '{printf "%.2f\n",$0/59.5}' ball_dropping_times >bull_velocities
You can make use of the expr command as:
expr 3 + 3
To store the result into a variable you can do:
sum=$(expr 3 + 3)
or
sum=`expr 3 + 3`
Lots of ways - most portable is to use the expr command:
expr 3 + 3
I believe the ((3+3)) method is the most rapid as it's interpreted by the shell rather than an external binary.
time a large loop using all suggested methods for the most efficient.
Solved thanks to Dennis, an example of BC-use:
$ cat calc_velo.sh
#!/bin/bash
for i in `cat ball_dropping_times`
do
echo "scale=20; $i / 59.5" | bc
done > ball_velocities
My understanding of math processing involves floating point processing.
Using bashj (https://sourceforge.net/projects/bashj/) you can call a java method (with floating point processing, cos(), sin(), log(), exp()...) using simply
bashj +eval "3+3"
bashj +eval "3.5*5.5"
or in a bashj script, java calls of this kind:
#!/usr/bin/bashj
EXPR="3.0*6.0"
echo $EXPR "=" u.doubleEval($EXPR)
FUNCTIONX="3*x*x+cos(x)+1"
X=3.0
FX=u.doubleEval($FUNCTIONX,$X)
echo "x="$X " => f(x)=" $FUNCTIONX "=" $FX
Note the interesting speed : ~ 10 msec per call (the answer is provided by a JVM server).
Note also that u.doubleEval(1/2) will provide 0.5 (floating point) instead of 0 (integer)
One use case that might be useful in this regard is, if one of your operand itself is a bash command then try this.
echo $(( `date +%s\`+10 )) or even echo $(( `date +%s\`+(60*60) ))
In my case I was trying to get Unixtime 10 seconds and hour later than current time respectively.