19

Is there a grep-like utility that will enable me to do grep searches with logic operators. I want to be able to nest and combine the logical constructs freely. For example, stuff like this should be possible:

grep (term1 && term2) || (term1 && (term3 xor term4)) *

I realize this can be done with vanilla grep and additional bash scripting, but my goal here is to avoid having to do that.

13

With awk, as with perl, you'll have to wrap terms in //, but it can be done:

awk '(/term1/ && /term2/) || (/term1/ && xor(/term3/, /term4/))' 
27

There are lot of ways to use grep with logical operators.

  1. Use \| to separate multiple patterns for the OR condition.

    Example: grep 'pattern1\|pattern2' filename

  2. Use the -E option to send multiple patterns for the OR condition.

    Example: grep -E 'pattern1|pattern2' filename

  3. Using a single -e matches only one pattern, but using multiple -e option matches more than one pattern.

    Example: grep -e pattern1 -e pattern2 filename

  4. grep -v can simulate the NOT operation.

  5. There is no AND operator in grep, but you can brute-force simulate AND by using the -E option.

    Example : grep -E 'pattern1.*pattern2|pattern2.*pattern1' filename

    The above example will match all the lines that contain both pattern1 and pattern2 in either order.)

  • 1
    -E is not quite equivalent to && due to the fact that it is order-sensitive – iruvar Jan 5 '15 at 13:58
  • grep foo | grep bar is a more general way to do AND. – Kenster Jan 5 '15 at 15:43
  • 2
    +1 for clearly explaining that there isn't a real "AND" operator, and that the best we can do is simulate a hack using an OR structure. This will of course get unwieldy with more than 3 terms, but for two terms it works well. – Eric Hepperle - CodeSlayer2010 Apr 20 '17 at 15:57
5

You could use perl:

perl -wne 'print if (/term1/ && /term2/) || (/term1/ && (/term3/ xor /term4/))'
0
sed '/term1/!d;/term2/b' -e '/term3/!d;/term4/d' *

I believe that accomplishes what you're trying to do. It deletes from output any line which doesn't match term1, it branches out of the script (and so autoprints) any line that remains and that matches term2, and for lines that remain it deletes any which do not match term3 and from those any that do match term4.

sed scripts are evaluated in order, and all tests are boolean, so any actions resulting from a test are going to directly affect the behavior of any following actions.

0

I use to chain grep commands to achieve a logical AND:

grep expr1 filename | grep expr2

I believe it is pretty straightforward, Unix-like and elegant.


Then you can combine (as @Tushi thoroughly explained) with the -E option for OR-ing and -v for negating.

Your specific example is pretty nasty and probably would benefit from some more powerful utility (see @muru's answer).

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.