Compute Average in Bash

Bash - Calculate the Average of Numbers Inputted

Still not sure what you want a to be. But I think you can just loop 3 times. Then each iteration get a set of numbers, and add them up and keep track of how many you have. So something like below. (note $numbers and $sum are initialized to 0 automatically)

#!/bin/bash    
sum=0
numbers=0
for a in {1..3}; do
read -p $'Enter a set of numbers:\n' b
for j in $b; do
[[ $j =~ ^[0-9]+$ ]] || { echo "$j is not a number" >&2 && exit 1; }
((numbers+=1)) && ((sum+=j))
done
done

((numbers==0)) && avg=0 || avg=$(echo "$sum / $numbers" | bc -l)
echo "Sum of inputs = $sum"
echo "Number of inputs = $numbers"
printf "Average input = %.2f\n" $avg

Where example output would be

Enter a set of numbers: 
1 2 3
Enter a set of numbers:
1 2 3
Enter a set of numbers:
7
Sum of inputs = 19
Number of inputs = 7
Average input = 2.71

A simple small shell script to compute averages

the code below works, you can probably optimize it if you want (or use awk, perl, etc):

#!/bin/bash

if [ $# -ne 1 ]; then
echo "Usage: \"$0\" <filename>"
exit
fi

if [ ! -f $1 ]; then
echo "$1 file not found."
echo "Usage: $0 <filename>"
exit
fi

sum=0
count=0
arq=$1

while read line
do
num=`echo ${line#* }`
sum=`expr $sum + $num`
count=`expr $count + 1`
done < "$arq"

if [ "$count" != 0 ]
then
avg=`expr $sum / $count`
printf "Sum= \"$sum\" \n Count= \"$count\" \n Avg= \"$avg\""
exit 0
else
printf "Sum= \"$sum\" \n Count= \"$count\" \n Avg= undefined"
exit 0
fi

Calculate the Average of Numbers from command output

nvidia-smi --format=csv --query-gpu=utilization.gpu | awk '/[[:digit:]]+[[:space:]]%/ { tot+=$1;cnt++ } END { print tot/cnt }'

Pipe the output of nvidia-smi ... to awk. Process lines that have a one or more digits, a space and then a "%". Create a running total (tot) and also, count the number of occurrences (cnt) At the end, divide tot by cnt and print the result.

Bash script to calculate average mark

In case you are ok with awk(where we need not to use so many commands in a loop), you could try following, could be done in a single awk itself.

awk 'BEGIN{FS=":"} {print "Average for student "$1 " is: " ($2+$3+$4)/3}' Input_file

Explanation: Adding detailed explanation for above.

awk '              ##Starting awk program from here.
BEGIN{ ##Starting BEGIN section of this program from here.
FS=":" ##Setting FS as colon here.
}
{
print "Average for student "$1 " is: " ($2+$3+$4)/3
##printing student name(1st column) and printing avg(adding 2nd, 3rd and 4th column) and dividing it with 3 here.
}
' Input_file ##Mentioning Input_file name here.

bash- find average of numbers in line

With some minor corrections, your code runs well:

while read -a rows
do
total=0
sum=0
for i in "${rows[@]}"
do
sum=`expr $sum + $i`
total=`expr $total + 1`
done
average=`expr $sum / $total`
echo $average
done <filename

With the sample input file, the output produced is:

1
5
7
5
2
5

Note that the answers are what they are because expr only does integer arithmetic.

Using sed to preprocess for expr

The above code could be rewritten as:

$ while read row; do expr '(' $(sed 's/  */ + /g' <<<"$row") ')' / $(wc -w<<<$row); done < filename
1
5
7
5
2
5

Using bash's builtin arithmetic capability

expr is archaic. In modern bash:

while read -a rows
do
total=0
sum=0
for i in "${rows[@]}"
do
((sum += $i))
((total++))
done
echo $((sum/total))
done <filename

Using awk for floating point math

Because awk does floating point math, it can provide more accurate results:

$ awk '{s=0; for (i=1;i<=NF;i++)s+=$i; print s/NF;}' filename
1
5.2
7.4
5.4
2.8
5.6

Calculate average execution time of a program using Bash

You could write a loop and collect the output of time command and pipe it to awk to compute the average:

avg_time() {
#
# usage: avg_time n command ...
#
n=$1; shift
(($# > 0)) || return # bail if no command given
for ((i = 0; i < n; i++)); do
{ time -p "$@" &>/dev/null; } 2>&1 # ignore the output of the command
# but collect time's output in stdout
done | awk '
/real/ { real = real + $2; nr++ }
/user/ { user = user + $2; nu++ }
/sys/ { sys = sys + $2; ns++}
END {
if (nr>0) printf("real %f\n", real/nr);
if (nu>0) printf("user %f\n", user/nu);
if (ns>0) printf("sys %f\n", sys/ns)
}'
}

Example:

avg_time 5 sleep 1

would give you

real 1.000000
user 0.000000
sys 0.000000

This can be easily enhanced to:

  • sleep for a given amount of time between executions
  • sleep for a random time (within a certain range) between executions

Meaning of time -p from man time:

   -p
When in the POSIX locale, use the precise traditional format

"real %f\nuser %f\nsys %f\n"

(with numbers in seconds) where the number of decimals in the
output for %f is unspecified but is sufficient to express the
clock tick accuracy, and at least one.

You may want to check out this command-line benchmarking tool as well:

sharkdp/hyperfine

Assigned and calculate the average data with bash script?

If gawk is available, would you please try the following:

gawk 'BEGIN {
IGNORECASE = 1 # make the regex case-insensitive
RS = "\r\n" # assign input record seoarator to CR+LF
ORS = "\n" # assign output record separator to LF
OFS = "\t" # assign output field separator to TAB
print "Sols", "Dose rate(average)" # print the header line
}
/START_SOL/ { # if the line contains "START_SOL"
gsub(/.*START_SOL=/, "")
sol = $0 # then assign "sol" to the value
}
c && !--c { # extract the 2nd line after "DOSE_B"
n++ # increment the number
sum += $0 # accumulate the dose rate
}
/DOSE_B/ {c = 2} # prepare for the 2nd next line
ENDFILE { # end of each file (available only with gawk)
print sol, sum / n # print sol and the average of dose rate
n = 0; sum = 0 # reset number and the sum
}
' /mnt/c/Users/taibo/Desktop/MSL_Script/Data/*.TXT | sort -nk1,1
  • It extracts sol value and dose_b rates out of each file.
  • Whenever the dose_b rate (second line after the keyword) is found,
    the value is added to sum and the counter n is incremented by 1.
  • At the end of each file, sol and the average of dose rate are printed.
  • Finally the whole lines are numerically sorted by the sol value.

If you feel the execution time is slow, please try the Perl alternative:

perl -015 -ne '
BEGIN {print "Sols\tDose rate(average)\n"}
if (/START_SOL=(\d+)/i) {$sol = $1}
elsif (/DOSE_B/i) {readline; $sum += readline; $n++}
elsif (eof) {printf("%s\t%f\n", $sol, $sum / $n); $sum = 0; $n = 0}
' /mnt/c/Users/taibo/Desktop/MSL_Script/Data/*.TXT | sort -nk1,1

How to use bash scripting to calculate an average?

Two problems: The spaces around the equal sign -- Bash is sensitive about this -- and the way you add (+) the two operands without evaluating with $().

I don't know exactly what your a.out returns, but substituting it with a simple echo 1, this adds up to 41:

moyenne=$(($moyenne + $(echo 1 2>&1 | tail -1)))


Related Topics



Leave a reply



Submit