2

I want to grep or search using shell commands for two consecutive lines that match two different patterns, e.g match for line1: "abc", for line2: "def". So, for the following text there should be one match: lines 4 and 5.

1234
abc-noise
6789
abc-noise
def-noise
def-noise
1234

When I find such a match I want to print it including N lines before the match. Any ideas? Thanks.

Inian
  • 80,270
  • 14
  • 142
  • 161
yorgo
  • 477
  • 1
  • 6
  • 14
  • 1
    What have you written so far? – codeforester Jan 12 '17 at 17:24
  • Did you make an attempt using `grep`, `sed` or any tools. Post your research efforts – Inian Jan 12 '17 at 17:33
  • Not much to show. I tried 'grep -B1 def | grep -A1 abc' , but then got stuck with how I could also get the N lines before the match. Where -B1 outputs also 1 line before the match, and -A1 1 line after the match – yorgo Jan 12 '17 at 18:06
  • Possible duplicate of: http://stackoverflow.com/questions/2686147/how-to-find-patterns-across-multiple-lines-using-grep – codeforester Jan 12 '17 at 18:07
  • Not really a duplicate. The tricky and different part is I also need to output N lines before the consecutive lines match. – yorgo Jan 12 '17 at 18:20

3 Answers3

6

Use GNU grep in PCRE mode, with -P flag enabled,

grep -ozP ".*abc.*\n.*def.*" file

Using pcregrep for an input file

cat file
1234
abc-noise
6789
abc-noise
def-noise
def-noise
1234
noise-abc-noise
noise-noise-def

For multi-line pattern-match, do

pcregrep -M  'abc.*\n.*def' file 
abc-noise
def-noise
noise-abc-noise
noise-noise-def

And for lines before the pattern match, use the -B flag as in GNU grep

pcregrep -B2 -M  'abc.*\n.*def' file 
abc-noise
6789
abc-noise
def-noise
def-noise
1234
noise-abc-noise
noise-noise-def

More about the flags -M and -B from the man pcregrep page,

-M, --multiline Allow patterns to match more than one line. When this option is given, patterns may usefully contain literal newline characters and internal occurrences of ^ and $ characters. The output for a successful match may consist of more than one line, the last of which is the one in which the match ended. If the matched string ends with a newline sequence the output ends at the end of that line.

-B number, --before-context=number Output number lines of context before each matching line. If filenames and/or line numbers are being output, a hyphen separator is used instead of a colon for the context lines. A line containing "--" is output between each group of lines, unless they are in fact contiguous in the input file.

Inian
  • 80,270
  • 14
  • 142
  • 161
  • Thanks, what about the requirement to print the N lines before the match? I tried your solution with the extra flag -B3, for 3 lines before but it does not work. – yorgo Jan 12 '17 at 18:16
  • @user2405602: Can you use `pcregrep`? can you see if it is installed? `which pcregrep`? – Inian Jan 12 '17 at 18:25
  • , Yes it is installed, but I found a solution using your initial suggestion. Two get 2 more lines before the match you can try: `grep -ozP ".*\n.*\n.*abc.*\n.*def.*" file ` So just add a `.*\n` for each extra line. Not too elegant but works. – yorgo Jan 12 '17 at 18:28
  • @user2405602: You don't have to post this is an answer. you can just accept my answer(tick on the left of my answer) to let people know that you have solved the problem. Also refer my solution using pcregrep – – Inian Jan 12 '17 at 18:42
2

Expanding on @Inian's great answer, if you want to do search recursively through a whole directory:

find my_code_dir/ -type f  -name "*.py" -exec pcregrep -B2 -M  'except.*\n.*pass' {} +

This particular command will find occurrences lines containing except followed immediately by a line containing pass, but only in .py files.

crypdick
  • 16,152
  • 7
  • 51
  • 74
0
#!/bin/bash
a=''
b=''
while read c; do
        a=$b;
        b=$c;
        if [ `echo "$a" |grep "abc"` ] & [ `echo "$b" |grep "def"` ]; then
                echo $a;
                echo $b;
                break;
        fi
done

Launch:

$./find2pat
wegweg
egwergwerg
sdfabcerg
rrheedef4

Output:

sdfabcerg
rrheedef4
  • Thanks, same comment here, what about the requirement to print the N lines before the match? – yorgo Jan 12 '17 at 18:18