1191

I have been trying to work out the syntax for this command:

grep ! error_log | find /home/foo/public_html/ -mmin -60

OR:

grep '[^error_log]' | find /home/baumerf/public_html/ -mmin -60

I need to see all files that have been modified except for those named error_log.

I've read about it here, but only found one not-regex pattern.

Arsen Khachaturyan
  • 7,335
  • 4
  • 37
  • 38
jerrygarciuh
  • 19,716
  • 25
  • 81
  • 130
  • 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

2114

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

fedorqui
  • 252,262
  • 96
  • 511
  • 570
Motti
  • 105,704
  • 46
  • 182
  • 255
  • 166
    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
  • 42
    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
  • 19
    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
  • 12
    @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 Nocke Dec 20 '20 at 11:38
  • 1
    This madlad out here grepping the help output from grep. – YouriKoeman Jan 15 '21 at 19:19
189

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.

L0j1k
  • 11,505
  • 7
  • 52
  • 65
fedorqui
  • 252,262
  • 96
  • 511
  • 570
19

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
Papa Smurf
  • 345
  • 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