1

I have file

try.txt

RAM 142 149 131
Cache 456 152 184

I want to compute maximum, minimum, median for each value of the line

Expected Output:

Min= 131 Max=149 Median=142
Min=152 Max=456 Median=184

Here is what I have tried.:

for itr in {1..2}
do
awk "FNR == $itr { c=0;size=NF;
        for(i=2;i<=size;i++)
        arr[c++] =$i;

        for(i=0;i<c;i++)
        {
                for (j=i+1;j<c;j++)
                {
                    if(arr[i]>arr[j])
                    {
                        temp=arr[i];
                        arr[i]=arr[j];
                        arr[j]=temp;
                    }
                }
        }    

        print "Min=" arr[0] "Max=" arr[2] "Median=" arr[1]   
}" try.txt
done

Inorder to approach the output, I created an array to hold the $2, $3, $4 of value of each line, but unfortunately, it is not taking. The main purpose of creating an array to compute median, as the element must be in sorted order to compute median. Please help me in creating an array for each line's value to compute min, max, median.

Ratnesh
  • 1,554
  • 3
  • 12
  • 28

4 Answers4

2

For the limited input, consisting only of 3 numbers, we could:

cat <<EOF >file
LoginActivity 142 149 131
StorageCheckActivity 456 152 184
EOF

# remove the leading word
<file cut -d' ' -f2- | 
# for each 3 arguments, print them on separate line, sort them, remove newlines
xargs -n3 sh -c 'printf "%s\n" "$@" | sort | tr "\\n" " "' -- |
# for each of 3 arguments from the input, print them in nice formatting using printf
xargs -n3 sh -c 'printf "Min=%d Max=%d Median=%d\n" "$1" "$3" "$2"' -- 

will output:

Min=131 Max=149 Median=142
Min=152 Max=456 Median=184
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
2

Just for fun, 3 comparisons:

awk '{ x=$2; y=$3; z=$4; }
     (x > y) {t=x;x=y;y=t}
     (y > z) {t=y;y=z;z=t}
     (x > y) {t=x;x=y;y=t}
     {print "Min="x" Max="z" Median="y}' file
kvantour
  • 25,269
  • 4
  • 47
  • 72
1

Doing it with a quick perl script (That you would then call from your shell script):

#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;

while (<>) {
    chomp;
    my @nums = sort { $a <=> $b } (split)[1,2,3];
    say "Min=$nums[0] Max=$nums[2] Median=$nums[1]";
}

Example:

$ ./example.pl try.txt
Min=131 Max=149 Median=142
Min=152 Max=456 Median=184

Or as a one-liner:

$ perl -lane 'printf "Min=%d Max=%d Median=%d\n", (sort { $a <=> $b } @F[1,2,3])[0,2,1]' try.txt 
Min=131 Max=149 Median=142
Min=152 Max=456 Median=184

But since you asked, here's a gawk-specific awk verison:

$ gawk '{
   arr[1] = $2; arr[2] = $3; arr[3] = $4;
   asort(arr, arr, "@val_num_asc");
   printf "Min=%d Max=%d Median=%d\n", arr[1], arr[3], arr[2];
  }' try.txt
Shawn
  • 47,241
  • 3
  • 26
  • 60
  • I want the solution mainly in bash, sed, awk.Thanks for your quick reply. – Ratnesh Feb 14 '19 at 10:53
  • 1
    @Arya The nice thing about shell scripts is that you can use pretty much any existing program or one-liner written in whatever appropriate language you want to build up whatever you need to get done. It's like lego that way. You can probably do it using nothing but bash built-in commands without any external programs, but it would be much larger and harder to understand compared to making something else do all the work. – Shawn Feb 14 '19 at 10:57
  • 1
    @Arya Added perl and gawk one-liners. – Shawn Feb 14 '19 at 11:13
  • @Shawn, be aware that asort does textual sort and not numeric sort. This implies that "95" > "941" – kvantour Feb 14 '19 at 14:43
  • 1
    @kvantour The docs say that numeric values are sorted before other types, which sounds like it sorts them as numbers. Updated to make it explicit, though. – Shawn Feb 14 '19 at 14:55
  • @kvantour Did some testing and it works as expected without the explicit sort type. Basically, fields with all digits have the `strnum` type, and that persists across variable assignment. Two `strnum` values are compared numerically. See section 6.3.2.1 of the gawk manual. I'm going to leave the explicit version up anyways. – Shawn Feb 14 '19 at 15:17
1

late to the party, but here is another awk

$ awk '{$1=""; split($0,a); asort(a); 
        print "Min="a[1], "Max="a[3], "Median="a[2]}' file

Min=131 Max=149 Median=142
Min=152 Max=456 Median=184
karakfa
  • 66,216
  • 7
  • 41
  • 56