3

For example, lets say I want to find all lines with 'matching' and the previous unindented lines in this text.

Container 1
   some text
   some text
   matching text
   some text
Container 2
   some text
   some text
Container 3
   some text
   matching text

The result I want would look like this

Container 1
   matching text
Container 3
   matching text

Is this possible?

  • 2
    Can there be more than one matching text in a Container part? – Esref Dec 10 '15 at 21:34
  • 2
    And can unintended lines contain matching? – Stéphane Chazelas Dec 10 '15 at 21:53
3
awk '
    !/^[[:blank:]]/ {unindented = $0} 
    /matching/ && /^[[:blank:]]/ {print unindented; print}
' file

That remembers the last line that did not begin with whitespace. When you get to a matching line, use that value.

  • 1
    If an unindented line matches, this prints it repeatedly. – user146939 Dec 16 '15 at 20:47
  • Very true. The regex should test for leading whitespace. Answer updated. – glenn jackman Dec 16 '15 at 20:58
  • Ah, I was trying this and it did not work, but that approach should. awk '!/^[[:blank:]]/ {unindented = $0} /^[:blank:].*matching/ {print unindented; print}' test – user146939 Dec 16 '15 at 21:00
  • Thanks. This was all very helpful, I was able to build on that and do even more of what I wanted with some if statements, and I just became a fan of awk. – user146939 Dec 17 '15 at 14:48
5

Here's one way with sed:

sed -n '/^[^[:blank:]]/b do      # if line is not indented go to label do
//!{                             # if line is indented and if it
/matching/H                      # matches, append it to hold space
}
$b do                            # if on last line go to label do
b                                # branch to end of script
: do                             # label do
x                                # exchange hold buffer w. pattern space
/\n.*matching/p                  # if current pattern space matches, print
' infile

If you want to also print the non-indented lines that match e.g. Container matching stuff even if none of the lines in the indented block that follows matches, then simply change the last condition to /matching/p so as to remove the \n.* restriction and print the pattern space even if it holds just one (non indented) line that matches:

sed -n '/^[^[:blank:]]/b do
//!{
/matching/H
}
$b do
b
: do
x
/matching/p
' infile
  • Thank you very much for your answer and the detailed explanation. I failed to mention one criteria, that if the container matches, it is also printed. I am trying to insert and && operator to do this on the first portion before branching, but failing. – user146939 Dec 11 '15 at 17:09
2

Here's another sed:

sed -ne'/^[[:space:]]/H;$x;//!{$!x;//!s/\n.*match/&/p;}' <in >out

Container 1
   some text
   some text
   matching text
   some text
Container 3
   some text
   matching text

It considers a Container to be a contiguous span of not-blank lines which begin with a not-space character, and only prints Containers which match match one or more times from their second line on.

You could write that out to grep:

sed ... | grep -E '^([^ ]| .*match)'

...to get results like your example...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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