1

Select rows after the maximum minimum valor found

Input file

22 101 5
23 102 5
24 103 5
25 104 23
26 105 25
27 106 21
28 107 20
29 108 8
30 109 6
31 110 7

To figure out my problem, I tried to subtract column 3 and print the lines after the minimum value found in column 4. In this case after row 7

awk '{$4 = $3 - prev3; prev3 = $3; print $0}' file

22 101 5 
23 102 5 0
24 103 5 0
25 104 2 18
26 105 2 2
27 106 2 -4
28 107 2 -1
29 108 8 -12
30 109 6 -2
31 110 7 1

Desired Output

29 108 8
30 109 6
31 110 7

I believe there is better and easy way to get same output.

Thanks in advance

4
  • 1
    Can you clarify your problem description? Does it have to be after the minimum and the maximum have been found? Is valor a typo and do you mean value, or is it a specific term (if so, please explain). Do the first and second row have any meaning or use here? Commented Aug 20, 2018 at 11:56
  • 1
    Not clear, you mention in your column 4 logic + addition but you re writing it subtraction? Also not clear which maximum and minimum values are you talking? column 4 or column3? Please edit your post with correct samples and get back to us then. Commented Aug 20, 2018 at 11:56
  • What should happen if there are just two rows, like: 22 101 5 <newline> 23 102 7 for example? Should both rows be printed or just the last one (what is the default value of "0th" row)? Commented Aug 20, 2018 at 12:05
  • Given the output and the values in column four, I'm guessing "the maximum minimum valor" means the maximum negative value of the difference between two consecutive rows. But that will have to be clarified by the OP. Commented Aug 20, 2018 at 12:21

1 Answer 1

3

You need to process the same file twice:

  1. Find out the line number of the min value
  2. Print the line and the lines after it

Like this:

awk 'NR==FNR{v=$3-prev3;prev3=$3;if(NR==2||v<m){m=v;ln=NR};next}FNR>=ln' file file

Explanation:

# This condition is true as long as we process the file the first time
NR==FNR {

    # Your calculation
    v=$3-prev3
    prev3=$3

    # If NR==2, meaning in row 2 we initialize m and ln.
    # Otherwise check if v is the new minimum and set m and ln.
    if(NR==2 || v<m){
        # Set m and ln when v is the new minimum
        m=v
        ln=NR
    }

    next # Skip the conditional below
}

# This condition will be only evaluated when we parse the file
# the second time. (because of the "next" statement above)

# When the line number is greater or equal than "ln" print it.
# (print is the default action)
FNR>=ln
Sign up to request clarification or add additional context in comments.

5 Comments

thanks :) ... It was simpler to understand when executing what the OP had (and change + to -)
That will fail if/when all the $3 values are greater than their predecessor. Try it with input where $3 is 2, 3, 4, etc.. You need to add a condition to populate m and ln when m is null, not just when m is less than v or you'll be relying on the value of v becoming negative at some point to cause m to be set for the first time. It's like any other min/max calculation - you've got to use the initial value as the min/max.
@EdMorton Thanks!
No problem and you do not need to init m and ln - awk does that for you and does it in a better way than that by using zero-or-null so you can differentiate first use from a specific numeric value. Just get rid of all the stuff about initing m and ln and change if(v<m){ to if (NR==2 || v<m) { (assuming the OP doesn't want to compare the first $3 to 0) and you're good to go!
Sounds much better. Will change that (later, atm working)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.