Reputation: 77
I'm trying to create a bash script that calculates the average and median on rows and columns of a text file. I have the functions for the average and median working, however I'm trying to format the output for the rows (the column format is just fine).
This is what I want:
Averages: Medians:
1 1
5 5
7 7
5 6
3 3
6 6
However my output of code currently does this:
Averages: Medians:
1
5
7
5
3
6
1
5
7
6
3
6
The code I currently have is:
if [[ $1 == -r* ]]
then
echo "Averages: Medians"
avg_nums $INPUT_FILE #calls average function on the file
find_median $INPUT_FILE #calls median function
elif...
#block of code for columns which works correctly.
fi
Another thing I've tried, which my teacher suggested, was storing the value of the average and median into a temp variable and then printing it all together when I was ready. It didn't work either. What I did for that was:
#average function
tempAvg+="$avg" #append the new value of average to a global var
.
.
#median function
tempMed+="${arr[$medIndex]}" #append the new value of median to a global var
and then calling it below
if [[ $1 == -r* ]]
then
echo "Averages: Medians"
printf "%s\t%s\n" "$tempAvg" "$tempMed"
elif...
#block of code for columns which works correctly.
fi
which gives an output of:
Averages: Medians:
157536 157636
So obviously nothing I have tried has work. I'm new to bash scripting as well, just so you know. Does anyone have any suggestions on how to get this to work? Am I going about this the wrong way? Thanks.
edit: my input file is below (separated by tabs)
1 1 1 1 1
9 3 4 5 5
6 7 8 9 7
3 6 8 9 7
3 4 2 1 4
6 4 4 7 7
Upvotes: 2
Views: 202
Reputation: 84561
There are a number of way of approaching the problem. Thankfully, you are not looking for column sums and medians, which means you do not need to store all values for the duration of the script and can concentrate on row averages and row median, if I understood you correctly.
The average is, of course, easy, the median requires some form of sorting of the values row-wise to pick the median value. However, limiting to 3-columns, that is reasonably easy as well.
If you calculate and select the average and median for each row, you can then print the value immediately and accomplish your goals. You will want to print your header before you read and print the results for each line. One way to approach this would be similar to the following:
#!/bin/bash
printf "Averages: Medians:\n"
while read -r c1 c2 c3 || [ -n "$c3" ]; do
avg=$(( (c1 + c2 + c3)/3 )) ## average row
## sort row
[ $c1 -gt $c2 ] && { tmp=$c1; c1=$c2; c2=$tmp; }
[ $c1 -gt $c3 ] && { tmp=$c1; c1=$c3; c3=$tmp; }
[ $c2 -gt $c3 ] && { tmp=$c2; c2=$c3; c3=$tmp; }
med=$c2 ## pick medain
## print the values in a sane format
printf " %3d %3d\n" "$avg" "$med"
done <"$1"
exit 0
Input File
$ cat dat/rand10_3.txt
57 99 27
1 35 80
53 28 73
3 98 88
44 57 2
100 99 45
41 3 62
23 8 47
89 25 97
9 17 12
Use/Output
$ bash colavg3.sh dat/rand10_3.txt
Averages: Medians:
61 57
38 35
51 53
63 88
34 44
81 99
35 41
26 23
70 89
12 12
Note: your averages will reflect the result of integer division, unless you pass the calculation to bc
or something similar to do floating-point division.
Upvotes: 1
Reputation: 67507
You can use paste
paste <(avg_nums ...) <(find_medians ...) | sed '1i\Averages:\tMedians:'
Upvotes: 1