19

How can I search for two different phrases when they are on two different lines by using a single grep command?

For example

Line 1: This is a sweet.

Line 2: lemon.

I used this but no result

grep "sweet.*lemon" file_type
Zanna
  • 70,465

3 Answers3

26

To use grep for two different lines, search for both patterns

$ grep -e sweet -e lemon file_type
This is a sweet
lemon.

Or use alternation

$ grep -E 'sweet|lemon' file_type
This is a sweet
lemon.

To get the next line after a pattern, you could use the context option

$ grep -A1 sweet file_type
This is a sweet
lemon.

But if you're searching explicitly for a multiline pattern, that's tricky because grep thinks in lines.... Your .* will catch everything between "sweet" and "lemon" on the line. We can get "lemon" on the next line with -P using \n to match the newline and by telling grep the file is null separated with -z:

$ grep -zPo 'This is a sweet\nlemon' file_type
This is a sweet
lemon.

Notes:

  • -E Use extended regular expressions (to use | character for alternation without needing to escape it)
  • -An Print additional lines after the pattern, where n is the number of trailing lines to print
  • -P Use perl-style regular expressions ("experimental" in grep - install pcregrep instead for better perl regex support)
  • -z Use the null character as separator (just pretending in this case, but grep will take our word for it)
  • -o only print the matched part
Zanna
  • 70,465
  • In case this is tried on other distros, you may encounter a: grep: The -P and -z options cannot be combined - e.g. grep (GNU grep) 2.5.1 on RHEL – Jason Pyeron Sep 23 '18 at 11:22
  • How do you make this an "AND" instead of an "OR". For example, if lemon isn't there, it still returns 0 (non-error). – Joshua Pinter Aug 10 '20 at 21:20
  • @JoshuaPinter Sorry -- I don't understand what you want. grep -zPo 'This is a sweet\nlemon' file returns 1 if lemon is not there. grep -E 'sweet|lemon' file returns 0 if sweet OR lemon is there. What result are you looking for? (You may want to ask a new question) – Zanna Aug 11 '20 at 07:49
  • @Zanna Sorry, my bad. I only tested grep -E 'sweet|lemon' file and that returned 0 when either one was there. Didn't realize that the grep -zPo method acted more like an AND. Thanks for clarifying! – Joshua Pinter Aug 11 '20 at 15:47
  • @JoshuaPinter no worries :) – Zanna Aug 11 '20 at 17:54
7

Like this:

grep "sweet\|lemon"
madneon
  • 1,983
  • 1
  • 13
  • 20
  • sorry but this will match exact "sweet|lemon" – αғsнιη Dec 10 '16 at 08:37
  • 4
    @KasiyA This line's working fine. grep by default works in "standard mode", where "special characters" like |, +, * are interpreted literally unless they're masked with a backslash. See for example this answer. To use the way you're probably used to, that "special characters" need to be masked to be interpreted literally, you need to switch to "extended mode" (grep -E). Maybe madneon could elaborate a bit more on his answers, for example what the OPs try would have matched? – Henning Kockerbeck Dec 10 '16 at 10:51
1

Here is a pretty robust method for teasing out two lines which appear adjacent. I've laid it out so that the line order does not matter, but if it does matter this can be easily adjusted.

First I created a file with lines:

dog 
fish 
elephant 
wombat 
cat 
pickle 
anglepoise lamp 

Then I performed the following tests to demonstrate a use of grep including -A and -B to tease out just the two lines in question.

2020-08-14 02:08:45 →  touch Desktop/test/file.txt

2020-08-14 10:01:03 → grep -A1 -B1 cat Desktop/test/file.txt wombat cat pickle

2020-08-14 10:01:10 → grep -A1 -B1 cat Desktop/test/file.txt | grep -A1 -B1 wombat wombat cat

2020-08-14 10:01:27 → grep -A1 -B1 cat Desktop/test/file.txt | grep -A1 -B1 pickle cat pickle

2020-08-14 10:01:49 →

What's going on? First A and B mean after and before. So we are grepping for our term (cat) and including in the response one line after and one line before our target line. This will yield two or three lines depending if the target line is a first or last line (2 lines) or if the target line is somewhere else in the file. (A file with a single line can only return one line, obviously.)

Then we grep those results using the same method with the second search term. This will cut the three lines from above to two lines unless both terms happen to appear on the same line.

user58292
  • 137