1301

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

grep '[^foo]'
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
jerrygarciuh
  • 21,158
  • 26
  • 82
  • 139
  • 13
    [^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). – Jaap Nov 09 '11 at 15:49

3 Answers3

2294

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

Motti
  • 110,860
  • 49
  • 189
  • 262
  • 184
    Worth mentioning that for multiple (negative) matches `-e` option can be used: `grep -v -e 'negphrase1' -e 'negphrase2'` – Babken Vardanyan Jun 18 '14 at 09:30
  • 45
    Similar to the comment from @Babken-Vardanyan Also - able to use pipes to join multiple matches e.g. `grep -v 'negphrase1|negphrase2|negphrase3'` – Nicholas Adams Aug 05 '15 at 06:56
  • 24
    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 – Evan Langlois Dec 13 '15 at 06:52
  • seems like if we have `grep1 | grep2 -v`, then -v effect takes place on grep1 too, so first do `grep not expected` and then `grep expected` – Amol Pujari Jan 19 '16 at 09:29
  • 15
    @EvanLanglois - forcing grep to interpret the pattern as an extended regular expression using `-E` works, i.e. `grep -vE 'negphrase1|negphrase2|negphrase3'` – Zlemini Nov 17 '16 at 18:57
  • @Zlemini - Yes, that will work, but the line by Nicholas Adams doesn't. – Evan Langlois Dec 08 '16 at 03:05
  • There's one use case this solution does not work for: If I want the _filename_ of the files with lines containing `foo` but not `bar`. – Olle Härstedt Oct 23 '17 at 09:33
  • 2
    @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?](https://stackoverflow.com/a/12194352/3848), there's always a way :)) – Motti Oct 25 '17 at 07:18
  • grep --help | grep "invert" – nimig18 May 16 '19 at 03:12
  • Tip: If you tried around and still can not filter anything, consider piping the errors to your grep as well for example `sudo opensnoop 2>&1 | ggrep -vE "^dtrace"` – lony Mar 10 '20 at 10:34
  • 1
    Wow. Most linux command uses `-v` for verbose... thes makers of grep use it for something that, if used unintentionally, will almost certainly mean malfunction... – Frank N Dec 20 '20 at 11:38
  • 2
    This madlad out here grepping the help output from grep. – YouriKoeman Jan 15 '21 at 19:19
  • @YouriKoeman https://www.reddit.com/r/ProgrammerHumor/comments/j9q2nu/grep_grep_grep/ – Motti Aug 16 '22 at 08:16
211

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.

Laurel
  • 5,965
  • 14
  • 31
  • 57
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • 8
    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! – Peter T. Sep 17 '18 at 14:59
  • 4
    The OP specifically asks for `grep`. Why is this upvoted? – Eduardo Pignatelli Feb 09 '22 at 09:33
  • 1
    It's possible that the OP wasn't aware of `awk` capabilities and providing an alternate solution that provides the same result is helpful. – Ed S Mar 17 '23 at 17:38
22

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
AsukaMinato
  • 1,017
  • 12
  • 21
Papa Smurf
  • 375
  • 2
  • 7
  • while one is going to use `mmin` to search for files modified within `60 mins`, use `-type f` too as mentioned here https://stackoverflow.com/a/33410471/2361131 – gawkface Apr 27 '21 at 06:18