Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need help to find average, min and max values in shell script from text file

Tags:

bash

shell

I'm working on a shell script right now. I need to loop through a text file, grab the text from it, and find the average number, max number and min number from each line of numbers then print them in a chart with the name of each line. This is the text file:

Experiment1 9 8 1 2 9 0 2 3 4 5
collect1 83 39 84 2 1 3 0 9
jump1 82 -1 9 26 8 9
exp2 22 0 7 1 0 7 3 2
jump2 88 7 6 5
taker1 5 5 44 2 3

so far all I can do is loop through it and print each line like so:

#!/bin/bash

while read line
do
echo $line
done < mystats.txt

I'm a beginner and nothing I've found online has helped me.

like image 488
David Michael Klatt Avatar asked Dec 09 '25 21:12

David Michael Klatt


2 Answers

One way, using perl for all the calculations:

$ perl -MList::Util=min,max,sum -anE 'BEGIN { say "Name\tAvg\tMin\tMax" }
    $n = shift @F; say join("\t", $n, sum(@F)/@F, min(@F), max(@F))' mystats.txt
Name    Avg     Min     Max
Experiment1     4.3     0       9
collect1        27.625  0       84
jump1   22.1666666666667        -1      82
exp2    5.25    0       22
jump2   26.5    5       88
taker1  11.8    2       44

It uses autosplit mode (-a) to split each line into an array (Much like awk), and the standard List::Util module's math functions to calculate the mean, min, and max of each line's numbers.


And here's a pure bash version using nothing but builtins (Though I don't recommend doing this; among other things bash doesn't do floating point math, so the averages are off):

#!/usr/bin/env bash

printf "Name\tAvg\tMin\tMax\n"
while read name nums; do
    read -a numarr <<< "$nums"
    total=0
    min=${numarr[0]}
    max=${numarr[0]}
    for n in "${numarr[@]}"; do
        (( total += n ))
        if [[ $n -lt $min ]]; then
            min=$n
        fi
        if [[ $n -gt $max ]]; then
            max=$n
        fi
    done
    (( avg = total / ${#numarr[*]} ))
    printf "%s\t%d\t%d\t%d\n" "$name" "$avg" "$min" "$max"
done < mystats.txt
like image 122
Shawn Avatar answered Dec 13 '25 03:12

Shawn


Using awk:

awk '{
  min = $2; max = $2; sum = $2;
  for (i=3; i<=NF; i++) {
    if (min > $i) min = $i;
    if (max < $i) max = $i;
    sum+=$i }
  printf "for %-20s min=%10i max=%10i avg=%10.3f\n", $1, min, max, sum/(NF-1) }' mystats.txt
like image 44
Abelisto Avatar answered Dec 13 '25 03:12

Abelisto