BASH: how to perform arithmetic on numbers in a pipe
echo 1 2 3 4 5|{
read line;
for i in $line;
do
echo -n "$((i * i)) ";
done;
echo
}
The {} creates a grouping. You could instead create a script for that.
Best way to divide in bash using pipes?
Using bc
:
$ bc -l <<< "scale=2;$(find . -name '*.mp4' | wc -l)/3"
2.33
In contrast, the bash shell only performs integer arithmetic.
Awk is also very powerful:
$ find . -name '*.mp4' | wc -l | awk '{print $1/3}'
2.33333
You don't even need wc
if using awk
:
$ find . -name '*.mp4' | awk 'END {print NR/3}'
2.33333
How to do arithmetic operations on value returned by uniq -c?
You might be interested in a single awk script that does all the above in a single go (with exception of the sorting). Also, awk is the tool to use if you want to do arithmetic operations.
awk 'BEGIN{ ere="[0-9][0-9]/[A-Z][a-z][a-z]/[0-9][0-9][0-9][0-9]" }
(match($0,ere)){ date=substr($0,RSTART,RLENGTH); a[date]++; n++ }
END { for (date in a) {
yyyy=substr(date,8,4);
mm=(index("JanFebMarAprMayJunJulAugSepOctNovDec",substr(date,4,3))+2)/3
mm=sprintf("%0.2d",mm)
dd=substr(date,1,2)
print a[date],a[date]/n,yyyy"-"mm"-"dd
}
}' log.txt
As you mention that you only want to do this with Linux/Unix Shell commands, I will take the freedom to assume you mean bash. There are many other types of shell, but let us take the most common one.
Well in short, No, it is not possible. bash does not support floating point arithmetic but you can fake it. Example:
$ echo $(( 2/3 ))
1
$ printf "%f\n" "$(( 10**15 * 2 / 3 ))E-15"
0.666667
So assuming you have your presented output and lets also assume you have to total, you can do:
# total number of dates
n=3417
grep -E [0-9][0-9]/[A-Z]{1}[a-z]{2}/[0-9]{4} log.txt | sed 's/.*\(..\)\/Oct\/\(....\).*/\2-10-\1/' | sort | uniq -c | sort -ru | head -10 | \
while read -r count date; do
printf "%f %d %s\n" "$(( 10**15 * count / n ))E-15" "$count" "$date"
done
But since you already use sed, I still would suggest awk
Arithmetic operations using numbers from grep
Assumptions:
- we want to match on lines that start with the string
number
- we will always find 2 matches for
^number
from the input file - not interested in storing values in an array
Sample data:
$ cat file.dat
number1: 123
not a number: abc
number: 456
We'll use awk
to find the desired values and print all to a single line of output:
$ awk '/^number/ { printf "%s ",$2 }' file.dat
123 456
From here we can use read
to load the variables:
$ read -r num1 num2 < <(awk '/^number/ { printf "%s ",$2 }' file.dat)
$ typeset -p num1 num2
declare -- num1="123"
declare -- num2="456"
$ echo ".${num1}.${num2}."
.123.456.
NOTE: periods added as visual delimiters
variable error in bash when doing calculation
You received that error because you passed an invalid arithmetic expression into a bash arithetic expansion. Only an arithmetic expression is allowed for this place. What you try to do seems like this:
ref="$(grep -v ">" /data/ref/EN | wc -c)"
sample="$(grep -v ">" /example/SR | wc -l)"
# this is only integer division
#u=$(( sample / ref ))
#z=$(( 100 * u ))
# to do math calculations, you can use bc
u=$(bc <<< "scale=2; $sample/$ref")
z=$(bc <<< "scale=2; 100*$u")
printf "%d, %d, %.2f, %.2f\n" "$ref" "$sample" "$u" "$z"
so hopefully you get an output like this:
41858, 38986, 0.93, 93.00
Notes:
There is no need to
cd
before executing agrep
, it accepts the full path with the target filename as an argument. So without changing directory, you cangrep
various locations.In order to save the output of your command (which is only a number) you don't need to save it in a file and
cat
the file. Just use the syntaxvar=$( )
andvar
will be assigned the output of this command substitution.Have in mind that
/
will result to 0 for the division38986/41858
because it's the integer division. If you want to do math calculations with decimals, you can see this post for how to do them usingbc
.To print anything, use the shell builtin
printf
. Here the last two numbers are formatted with 2 decimal points.
How do I use floating-point arithmetic in bash?
You can't. bash only does integers; you must delegate to a tool such as bc
.
use shell pipe output as calculator input
As mentioned by Charles that parsing ls
is not a good practice but anyway if you want to do that, you can try
ls *.gz |wc -l | xargs echo "0.5*" | bc
Can't do arithmetic operation in bash
Remove the carriage return \r
from the size:
size=${size%$'\r'}
Arithmetic expressions in Bash?
In Bash, let
allows multiple assignments on a line:
let a=3 b=4 c=5
As you show in your question, quoting the argument to let
allows you to put spaces around the operators. You can, however, omit the quotes if you avoid using spaces.
Another form using double parentheses at the beginning of the statement (instead of the i=$((j + 1))
form) allows you to include spaces around the equal sign or do post- or pre- increment or decrement and additional assignment operations:
(( a = ( b + c ) * 4 ))
(( count++ ))
(( d = --c**2 ))
(( e *= 2 ))
(( f = 3, g = 5 )) # multiple operations require a comma separator
If you do help "(("
it says that the double parentheses is 'Equivalent to "let EXPRESSION
".'
You can use the declare
builtin to make assignments, including indirectly:
blue=2
name=blue
declare $name=4
echo $blue # result: 4
echo ${!name} # result: 4
Edit:
The $(())
construct is called "arithmetic expansion" and causes the contents to be evaluated as an integer expression. It's a syntax element of the shell.
If a variable is declared as an integer you don't need to use either form of double parentheses, you can omit the dollar sign from the variable name (as in the double-parentheses forms), but you can't add spaces around operators:
declare -i x=1 # set integer, initialize to 1
declare +i s=1 # clear integer, initialize to 1
x+=1 # could also be x=x+1
echo $x # result: 2 (addition)
s+=1 # could also be s=$s+1, requires a "$"
echo $s # result: 11 (string concatenation)
Unlike the forms above, calling expr
involves spawning an external executable which can be quite expensive for a lot of calculations in a loop. The only time it should be used is in environments where the shell can't do its own arithmetic or for portability when a script may find its way into such an environment. POSIX shells have arithmetic capability so it would be a concern only with older systems.
Regarding the use of bc
for floating point arithmetic, it or something similar is required when using Bash and many other shells. POSIX says that "Only signed long integer arithmetic is required."
Two shells that do support float math are ksh and zsh. In addition to bc
, you can use dc
, AWK, Python, Perl and others from within a Bash script.
One thing that Bash will do with floating point numbers is print them with the printf
builtin (note that there is also an external printf
, but builtins have priority).
printf "%'14.4f\n" 1234.56 # result " 1,234.5600" (in my locale)
Related Topics
Unable to Set Variable in Case Statement Bash
Bash - Calculate the Average of Numbers Inputted
Where Is $Path Set? Specifically Where Is My MAC Port Path Being Set
Environment Variable Used in Shell Script Appear Blank in Log File When Run by Cron
Webpack Build Fails with Gitlab-Ci
How to Modify Eip's Tracee Forked Procee
Focas Fwlib32 Cnc Library on Linux Platform
How to Install Python Package Installer Pip on Ubuntu 20.04 Linux
How to Determinate Destination MAC Address
Escaping the Exclamation Point in Grep
How to Hide Password from Jenkins Shell Output
Overhead of Supporting Floating Point Arithmetic Inside the Linux Kernel
How to Run Ionic in the Background
Recursively Rename Files to Ascii Standard
How to Set a Non-Standard Baudrate on a Serial Port Device on Linux
How to Stop Apache from Listing the Contents of My User Directories