1

I have a file:

$ cat test.csv
hello foo
needed
bar
blah
blah
bar
hello foo
needed
bar
blah
hello foo
needed
hello foo
needed
bar
blah

I need to extract lines having 'bar' and immediate line next to 'hello' but not the 'hello' line. So far i am able to extract as below but not able to ignore 'hello' lines. I can try extracting with another awk, but wonderign if there a oneliner that can take care of it in one go?

$ awk '/hello|bar/;/hello/{getline;print}' test.csv
hello foo
needed
bar
bar
hello foo
needed
bar
hello foo
needed
hello foo
needed
bar

EDIT: expected output-

needed
bar
bar
needed
bar
needed
needed
bar
anubhava
  • 761,203
  • 64
  • 569
  • 643
StrangerThinks
  • 246
  • 4
  • 14
  • 3
    Could you please post sample of expected output in your question so that it becomes more clear and let us know then. – RavinderSingh13 Aug 03 '20 at 13:36
  • 1
    Apologies. I have added expected output. – StrangerThinks Aug 03 '20 at 13:38
  • 1
    See also [lines around matching regexp](https://stackoverflow.com/questions/17908555/printing-with-sed-or-awk-a-line-following-a-matching-pattern) - this will help you use safer methods than `getline` ... for documentation, see https://www.gnu.org/software/gawk/manual/ and https://stackoverflow.com/tags/awk/info has other resources as well – Sundeep Aug 03 '20 at 13:46
  • 1
    @StrangerThinks: The `/hello|bar/;` without a block implies "print the line if the pattern matches". You could use an empty block, `/hello|bar/{};...`, or restrict the matching to `bar`, since the `hello` part is handled anyway using your next awk clause. – user1934428 Aug 03 '20 at 14:00
  • Got it. Original file had other lines which also needed to be included, and I had the assumption that in each awk subcommand the result set gets pruned so added an inclusive filter in the first cmd to include all necessary results followed by additional clause for hello. thanks for the clarification – StrangerThinks Aug 03 '20 at 14:12

2 Answers2

3

You may use this awk:

awk 'p || /bar/; { p = $0 ~ /hello/ }' file
needed
bar
bar
needed
bar
needed
needed
bar

Details:

  • p = $0 ~ /hello/: Will set p to 1 to 0 depending on whether a line matches hello or not
  • p || /bar/ will print a line if p == 1 or if line matches bar
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    Thank you. It works perfect and thanks for the explanation. Do you mind redirecting me to some resources pertaining to more documentation similar to above operations? – StrangerThinks Aug 03 '20 at 13:39
  • Stackoverflow awk tag has tons of great answers: https://stackoverflow.com/questions/tagged/awk – anubhava Aug 11 '20 at 18:20
2

Based on OP's samples could you please try following. Written and tested in https://ideone.com/EzCjLM link.

awk '
/hello/{
  found_hello=1
  next
}
found_hello || /bar/{
  print
  found_hello=""
}
' Input_file

Explanation: Adding detailed explanation for above.

awk '                     ##Starting awk program from here.
/hello/{                  ##Checking condition if line contains hello string then do following.
  found_hello=1           ##Setting variable found_hello here.
  next                    ##next will skip all further statements from here.
}
found_hello || /bar/{     ##Checking condition if found_hello is SET OR bar is found then do following.
  print                   ##Printing current line here.
  found_hello=""          ##Nullifying found_hello here.
}
' Input_file              ##Mentioning Input_file name here.
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93