1389

How do I match all lines not matching a particular pattern using grep? I tried this:

grep '[^foo]'
1
  • 15
    [^error_log] would never ever work anyway, [] are char classes, regexp 's in general are not good at negative patterns (unless the engine implements negative lookaheads). Commented Nov 9, 2011 at 15:49

3 Answers 3

2442

grep -v is your friend:

grep --help | grep invert  

-v, --invert-match select non-matching lines

Also check out the related -L (the complement of -l).

-L, --files-without-match only print FILE names containing no match

Sign up to request clarification or add additional context in comments.

14 Comments

Worth mentioning that for multiple (negative) matches -e option can be used: grep -v -e 'negphrase1' -e 'negphrase2'
Similar to the comment from @Babken-Vardanyan Also - able to use pipes to join multiple matches e.g. grep -v 'negphrase1|negphrase2|negphrase3'
Last comment is NOT the same as it will search for things that don't match both rather than either. ie If it matches one but not the other its still printed. Try it both ways with non-similar strings
@EvanLanglois - forcing grep to interpret the pattern as an extended regular expression using -E works, i.e. grep -vE 'negphrase1|negphrase2|negphrase3'
@OlleHärstedt, I think I misunderstood your scenario in my previous comment, the following may be what you're looking for grep "" /dev/null * | grep foo | grep -v bar | cut -d: -f1 | sort -u (why the first grep?, there's always a way :))
|
227

You can also use awk for these purposes, since it allows you to perform more complex checks in a clearer way:

Lines not containing foo:

awk '!/foo/'

Lines containing neither foo nor bar:

awk '!/foo/ && !/bar/'

Lines containing neither foo nor bar which contain either foo2 or bar2:

awk '!/foo/ && !/bar/ && (/foo2/ || /bar2/)'

And so on.

7 Comments

That's actually quite cool. You don't even have to learn the complete awk language in order to group regexp with logical operators. Thanks for this answer!
The OP specifically asks for grep. Why is this upvoted?
It's possible that the OP wasn't aware of awk capabilities and providing an alternate solution that provides the same result is helpful.
The awk command syntax you outline is very clear -- but I must be doing it wrong as it's not working for me! I'm trying to select certain lines of output from a locate command. Each line should not contain either of 'icon' or 'timeshift' or 'Papirus' to reduce output for clarity. This does not work: locate mime | awk '!timeshift && !icon && !Papirus' | wc -l , producing 58234 lines. A revised grep command produced 933 lines which is the correct output. Wonder where I strayed? Or maybe it's a change in or different version of awk? GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
@OldUncleHo you need to enclose the string within / /, so that Awk sees is as a string. Otherwise, it will treat timeshift and the other values as variable names. All together, you need to use awk '!/timeshift/ && !/icon/ && !/Papirus/ or using some regex-fu awk '!/(timeshift|icon|Papirus)/'.
|
23

In your case, you presumably don't want to use grep, but add instead a negative clause to the find command, e.g.

find /home/baumerf/public_html/ -mmin -60 -not -name error_log

If you want to include wildcards in the name, you'll have to escape them, e.g. to exclude files with suffix .log:

find /home/baumerf/public_html/ -mmin -60 -not -name \*.log

1 Comment

while one is going to use mmin to search for files modified within 60 mins, use -type f too as mentioned here stackoverflow.com/a/33410471/2361131

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.