Saturday, August 7, 2010

Excluding the unwanted directories from the search on Linux

If you want to search and exclude a particluar directory in your search then you can do it in following three ways

Method 1
Suppose I want to search a file lighttpd but exclude that search from my home directory
find / -name lighttpd | grep -v "^/home/" | xargs ls -l

Method 2
a for-loop and the command "dirname" will help here...
(if [ ! `dirname $i` = "/home" ]; then ...)

Method 3
Excluding the unwanted directories from the search
find / -wholename /home -prune -o -name lighttpd -exec echo rm {} \;

Explanation of method 3

The action -prune just tells find to not descend into directories. Let's look at every single
step of method 3 above

a. Look for a directory whose whole name is /home
$ find / -wholename /home

The name is relative to the specified search path, in this case / (root). This tell us that there is (obviously) only one item whose name is /home.

b. Add -prune
$ find / -wholename /home -prune

Nothing different here, because the action -prune alone is evaluated as true and the result is to print the directory name. Actually the rule here is: if the expression contains no actions other than -prune, -print is performed on all files for which the expression is true.

c. Add an alternative (logical OR)
$ find / -wholename /home -prune -o -name lighttpd -print

Note that the expression here contains at least one action other than -prune (-print), so that the rule cited above does not apply. For this reason, when find encounters /home the left-hand-side of the expression is true and the output is null now. Instead for all the other directories, the left-hand-side of the expression is false and the right-hand-side is evaluated (in this case every file whose name is lighttpd is printed out).

Note that if you omit -print (without adding any other action) the rule above is applied and -prune still has the effect to not descend into the directory, but the directory name is printed out:

$ find / -wholename /home -prune -o -name lighttpd

In my previous example the action -exec prevents this behaviour.

Finally you can omit multiple directories from the search by expanding the left-hand-side of the expression with other alternatives (embedded in escaped parentheses). For example:
$ find / \( -wholename /home -o -wholename /etc \) -prune -o -name lighttpd -print

d. If you want to know what {} do read man find and search for -exec section

-exec command ;
Execute command; true if 0 status is returned. All following arguments to find are taken to be arguments to the command until an argument consisting of
`;' is encountered. The string `{}' is replaced by the current file name being processed everywhere it occurs in the arguments to the command, not just
in arguments where it is alone, as in some versions of find. Both of these constructions might need to be escaped (with a `\') or quoted to protect them
from expansion by the shell. See the EXAMPLES section for examples of the use of the -exec option. The specified command is run once for each matched
file. The command is executed in the starting directory. There are unavoidable security problems surrounding use of the -exec action; you should use
the -execdir option instead.

No comments: