0

Is there any way for grep to have an AND feature? I mean something like this:

I have these lines:

I have this one line
I don't have this other line
I have this new line now
I don't have this other new line
This line is new

So I want for grep to find lines that contain BOTH the words "new" and "line", not only "new line". I know I can do this like this:

grep new file | grep line

But that's not what I'm looking for. I'm looking to do this with one single grep command. This is because this script will let the user input the two terms, and one of the terms might be null, which then throws a grep error and breaks the script.

iamAguest
  • 483

3 Answers3

1

If the second term is empty or unset, don't run the second grep:

grep -e "$term1" <file |
if [ -n "$term2" ]; then
    grep -e "$term2"
else
    cat
fi

This applies grep with the pattern in $term1 to the file called file and then, depending on whether $term2 is non-empty, applies a second grep to the result, or uses cat as a pass-through filter.

Note that this effectively implements "term1 AND term2" except when term2 is empty in which it degenerates into just "term1".


If you'd rather not run grep at all and instead return an empty result when the second term is empty:

if [ -n "$term2" ]; then
    grep -e "$term1" <file | grep -e "$term2"
fi

This effectively implements "term1 AND term2" and treats an empty term2 as "false".

The benefit of this is that it only relies on standard grep and that the two patterns are kept separate, which makes it easy to understand and maintain.

Kusalananda
  • 333,661
  • @Fólkvangr I've got too many ways to interpret that comment, could you please clarify? – Kusalananda Oct 22 '18 at 11:27
  • @Fólkvangr How can one talk about an OR relationship when there's only one term? – Kusalananda Oct 22 '18 at 12:16
  • @Fólkvangr Sure. If the wanted behaviour is to return nothing if the second term is empty, then it's just a matter of if [ -n "$term2" ]; then grep ... | grep ...; fi, i.e. don't run any grep at all. This may or may not be what the user wants. – Kusalananda Oct 22 '18 at 12:41
0

This will work (using GNU grep):

grep -P '(?<=new)\s(?=line)' file

Test:

$ cat > file
I have this one line
I don't have this other line
I have this new line now
I don't have this other new line
This line is new
^D

$ grep -P '(?<=new)\s(?=line)' file
I have this new line now
I don't have this other new line
Kusalananda
  • 333,661
Karel
  • 1,468
0

Try what man grep calls "Concatenation" combined with "Alternation":

P1=line
P2=new
grep "$P1.*$P2\|$P2.*$P1" file
I have this new line now
I don't have this other new line
This line is new
RudiC
  • 8,969