linuxstringawkmaxminimum

finding min and maximum between two strings in a data file using linux


*KEYWORD
$TIME_VALUE = 1.4000002e+001
$STATE_NO = 15
$Output for State 15 at time = 14
*ELEMENT_SHELL_THICKNESS
1346995      25 1457683 1471891 1457727 1471929
9.953265e-001   9.953265e-001   9.953265e-001   9.953265e-001
1346996      25 1471891 1457685 1471930 1457727  
9.953963e-001   9.953963e-001   9.953963e-001   9.953963e-001
1346997      25 1457685 1471892 1471931 1471930
9.953437e-001   9.953437e-001   9.953437e-001   9.953437e-001
*End

So the desired output could be

min=9.953265e-001  on line  07   at  1346995
max=9.953963e-001  on line  09   at  1346996

A probable solution, if we know the line numbers, is

cat your_file | awk '
NR >= 6 && NR <= 11{at=$1;getline
if (max < $1){max=$1;max_line=NR;max_at=at}
if (min > $1){min=$1;min_line=NR;min_at=at}}
NR == 7{min=$1;min_line=NR;min_at=at}
END{
printf "min=%-13e on line  %02d at %8d\n", min, min_line, min_at
printf "max=%-13e on line  %02d at %8d\n", max, max_line, max_at}'

but what if I want to search between *Keyword and *End, because due to a small change in the file the string comes to the defined lines and its value is 0 so the minimum is set to zero.

I must mention that this good solution was provided by jfgagne in my previous question: min and max in certain lines of input file with the tag of line number.


Solution

  • Add a state to your script. If your state variable is false, set it to true if you are looking at the start marker; in any event, skip to next line. If your state variable is true; if looking at end marker, set the state variable to false, and skip to the next line; otherwise, you are in the region; process the line as before.

    awk '!there{if($1 == "*ELEMENT_SHELL_THICKNESS") there=1; next}
    there&&/^\*End$/{there=0;next}
    {at=$1;getline
      if (!max || max < $1){max=$1;max_line=NR;max_at=at}
      if (!min || min > $1){min=$1;min_line=NR;min_at=at}}
    END{
      printf "min=%-13e on line  %02d at %8d\n", min, min_line, min_at
      printf "max=%-13e on line  %02d at %8d\n", max, max_line, max_at}' your_file
    

    I assume the start marker is *ELEMENT_SHELL_THICKNESS as suggested by the code, rather than *KEYWORD as you say in the question. I removed the min and max initialization code, mostly out of laziness; if either can be zero, perhaps you should put it back in.

    This also does away with the Useless Use of cat.