Making find ignore directories or other stuff with -prune

published Jun 16, 2016 11:05   by admin ( last modified Jul 12, 2016 12:04 )

(Warning: correct syntax with faulty explanations follow)

This was a real head scratcher for me. There is a -prune flag you can add to the find command on e.g. the Linux command line. It prunes stuff. So my first thought was that it takes an argument after itself for what needs to be pruned. It does not.

Instead it takes arguments before itself and uses them for what to prune out of the find results. But wait, it gets weirder: -prune returns true, which means that the stuff in front of -prune will still be there. What you need is to put an -o flag after prune. Now what is that? The total amount of documentation in the find man page about -o on my Ubuntu 16.04 is this:

       The POSIX standard specifies parentheses `(', `)', negation `!' and the `and' and `or' operators ( -a, -o).

So -o is the or operator. And -prune returns true. I don't know what programming languages you are used to, but in the ones I am used to, if the left hand side returns true with the or operator, the right hand side is not evaluated at all. If you want the right hand side to be evaluated too, you would stick an and operator in between.

So anyway, here is the way to do it

find [stuff you do not want to find] -prune -o [stuff you want to find] -print

You also need the -print flag at the end, because reasons. I guess the implicit -print you usually get in find, gets lost somewhere. Without an explicit -print, it prints. Everything.

Incidentally, if you change the -o to an -a, nothing gets printed.

Actually I think I just got it, one should think like this:

find [path] - "I'm gonna find anythyng in my path. Anything"

[stuff you do not want to find] - find all this stuff, yeah  this is what matched

-prune - "Return true! Because reasons"

-o - Ignore that shit, just terminate it, let's instead talk about this:

[stuff you want to find] - The stuff I really want. It magically got here because -prune did not return true for it. Or whatever.

-print - Hi, I'm print. I crowd out implicit prints, maybe. And I bind tight to the right hand side, so never heard of the left hand stuff.

So the or operator gets false for the files and dirs not matched by -prune, so it tries the right hand side. But wait, if this is the way it works, maybe -prune is kind of redundant. Yup, on my machine these give the same results back:

$ find -path "*/node_modules/*" -prune -o -name "*.js" -print
$ find -path "*/node_modules/*" -o -name "*.js" -print

Go figure. Maybe they are not always equivalent.