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
  • 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? 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.

4
  • 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. 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
1
  • 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...

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .