191

I would like to search for files that would not match 2 -name conditions. I can do it like so :

find /media/d/ -type f -size +50M ! -name "*deb" ! -name "*vmdk"

and this will yield proper result but can I join these 2 condition with OR somehow ?

Patryk
  • 13,556
  • 22
  • 53
  • 61

4 Answers4

281

yes, you can:

find /media/d/ -type f -size +50M ! \( -name "*deb" -o -name "*vmdk" \)

Explanation from the POSIX spec:

! expression : Negation of a primary; the unary NOT operator.

( expression ): True if expression is true.

expression -o expression: Alternation of primaries; the OR operator. The second expression shall not be evaluated if the first expression is true.

Note that parenthesis, both opening and closing, are prefixed by a backslash (\) to prevent evaluation by the shell.

rahmu
  • 19,673
  • 28
  • 87
  • 128
Serge
  • 8,371
  • 2
  • 23
  • 28
70

You can do this using a negated -regex, too:-

 find ./ ! -regex  '.*\(deb\|vmdk\)$'
Alex Leach
  • 7,720
  • 4
  • 28
  • 27
  • 10
    Note that `-regex` is less portable than `-name`. – jw013 Oct 12 '12 at 13:54
  • 2
    Should not be the accepted answer. Question asks for a solution using multiple name patterns with `find -name`. Serge's answer answers that. – Veverke Nov 24 '20 at 12:04
46

You were close to a solution:

find /media/d/ -type f -size +50M -and ! -name "*deb" -and ! -name "*vmdk"

You can combine the following logic operators in any sequence:

-a   -and      - operator AND
-o   -or       - operator OR
!              - operator NOT
makrom
  • 103
  • 2
DenisKolodin
  • 591
  • 4
  • 3
  • 2
    It doesn't look like you've actually changed the effect of the user's `find` command. Note that `-a` is the default operator if an explicit operator is missing. Also note that if you use `-o`, there must be a logical grouping of the two name tests. You do this with `\( ... \)`. – Kusalananda Feb 07 '20 at 12:29
  • Absolutely incredible. This 'find' command is changing my life. – wheeleruniverse Nov 19 '20 at 06:31
8

You can use regular expressions as in:

find /media/d -type f -size +50M ! -regex '\(.*deb\|.*vmdk\)'

Backslash is the escape character; . matches a single character, and * serves to match the previous character zero or more times, so .* means match zero or more characters.