I've seen a few examples of this, but I can't seem to get it to work in my particular situation. Lets say there is the below file.

line 1
line 2
line 3
line 1
line 2
line 4

I'm trying to catch everything between 'foo' and 'bar' as long as it contains 'baz' with a one liner.

Everything I've found so far is great for finding everything between foo and bar, but nothing seems to be good for only finding it if it contains baz.

Edit: The below works for me:

sed -n '/foo/{:a;N;/bar/!ba; /baz/p}' input.txt
  • should foo and bar be also included into result? May 25 '17 at 20:49
  • pcregrep -Mo '(?s)foo((?!bar).)*?baz((?!bar).)*?bar' would do it in a not very efficient way. May 25 '17 at 20:55
  • Yes, I'll need the foo line. foo is actually more like "foo data" with the foo part being static and the data something I need to see.
    – James Lacy
    May 25 '17 at 21:37
awk '
/foo/ { save=1 }
/baz/ { p=1 }
/bar/ { if (p) { print out ORS $0; } p=0; save=0; out="" }
{ if (save) { if (out) { out = out ORS $0 } else { out = $0 } } }
' input

Start saving lines if we see a /foo/; decide that they're worth printing if we see a /baz/, and once we see a /bar/, print the saved lines if we saw a /baz/.

I can't find a smarter way to keep a blank line (ORS) from showing up at the beginning of the "out" variable without manually testing it (as I do).

Not the answer you're looking for? Browse other questions tagged or ask your own question.