find is admittedly tricky. Once you get a handle on its abilities, you'll learn to appreciate its trickiness. But before thinking about anything remotely tricky, let's look at a simple find command:
All find commands, no matter how complicated, are really just variations on the one above. You can specify many different names, look for old files, and so on; no matter how complex, you're really only specifying a starting point, some search parameters, and what to do with the files (or directories or links or...) you find.
The key to using find in a more sophisticated way is realizing that search parameters are really "logical expressions" that find evaluates. That is, find :
So, something like
Once you've gotten used to thinking this way, it's easy to use the AND, OR, NOT, and grouping operators. So let's think about a more complicated find command. Let's look for files that end in .o or .tmp AND that are more than five days old, AND print their pathnames. We want an expression that evaluates true for files whose names match either *.o OR *.tmp :
-name "*.o" -o -name "*.tmp"
If either condition is true, we want to check the access time. So we put the expression above within parentheses (with backslashes so the shell doesn't treat the parentheses as ). We also add a :
-atime +5 \( -name "*.o" -o -name "*.tmp" \)
The parentheses force find to evaluate what's inside as a unit. The expression is true if "the access time is more than 5 days ago and \( either the name ends with .o or the name ends with .tmp \)." If you didn't use parentheses, the expression would mean something different:
-atime +5 -name "*.o" -o -name "*.tmp" Wrong!
sees two operators next to each other with no -o
that means AND.
So the "wrong" expression is true if "either \( the access time is more
than 5 days ago and the name ends with .o
\) or the name ends with
This incorrect expression would be true for any name ending with
, no matter how recently the file was accessed - the
The following command, which is what we want, lists files in the current directory and subdirectories that match our criteria:
What if we wanted to list all files that do not
criteria? All we want is the logical inverse of this expression. The
NOT operator is
But before you try anything too complicated, you need to realize one
isn't as sophisticated as you might like it to be.
You can't squeeze all the spaces out of expressions, as if it were a
real programming language. You need spaces before and after operators
A true power user will realize that find
is relying on the
And the shell, in
turn, is assuming that tokens are separated by spaces. When
the shell gives find
a chunk of characters like
Once you start thinking about expressions, find 's syntax ceases to be obscure - in some ways, it's even elegant. It certainly allows you to say what you need to say with reasonable efficiency.