Find and negation of an -iname condition

find

I am trying to find all the files which have 'pillar' in the name (case incentive) and do not contain 'cache' (also case insensitive) with

find . -iname '*pillar*' -and -not -iname '*cache*'

but it not working as I find (among others)

./Caches/Metadata/Safari/History/https:%2F%2Fwww.google.ch%2Fsearch?q=pillars+of+eternity+dropbox&client=safari&rls=en&biw=1440&bih=726&ei=CnBDVbhXxulSnLaBwAk&start=10&sa=N%23.webhistory

What am I doing wrong?

Best Answer

It looks like you want to avoid looking for files in *cache* directories more than finding files with *pillar* and not *cache* in their name. Then, just tell find not to bother descending into *cache* directories:

find . -iname '*cache*' -prune -o -iname '*pillar*' -print

Or with zsh -o extendedglob:

ls -ld -- (#i)(^*cache*/)#*pillar*

(not strictly equivalent as that would report a foo/pillar-cache file)

Or (less efficient as it descends the whole tree like in @apaul's solution):

ls -ld -- (#i)**/*pillar*~*cache*

Details on the zsh specific globs:

  • (#i): turn on case insensitive matching
  • ^: negation glob operator
  • (...): grouping (like @(...) in ksh).
  • <something>#: zero or more of <something> (like * in regexps).
  • ~: and-not operator (matches on the whole path)
  • **/: 0 or more directory levels (short for (*/)#).

Add the (D) glob qualifier if you want to descend into hidden dires and match hidden files like in the find solution.

Related Question