Find Command – Explain -path and -prune Options

find

I have a simple script that I understand most of, it's the find command that's unclear. I've got a lot of documentation but it's not serving to make it much clearer. My thought is that it is working like a for-loop, the currently found file is swapped in for {} and copied to $HOME/$dir_name, but how does the search with -path and -prune -o work? It's annoying to have such specific and relevant documentation and still not know what's going on.

#!/bin/bash
# The files will be search on from the user's home
# directory and can only be backed up to a directory
# within $HOME

read -p "Which file types do you want to backup " file_suffix
read -p "Which directory do you want to backup to " dir_name

# The next lines creates the directory if it does not exist
test -d $HOME/$dir_name || mkdir -m 700 $HOME/$dir_name

# The find command will copy files that match the
# search criteria ie .sh . The -path, -prune and -o
# options are to exclude the backdirectory from the
# backup.
find $HOME -path $HOME/$dir_name -prune -o \
-name "*$file_suffix" -exec cp {} $HOME/$dir_name/ \;
exit 0

This is just the documentation that I know I should be able to figure this out from.

-path pattern

File name matches shell pattern pattern. The metacharacters do not treat / or .
specially; so, for example,
find . -path "./sr*sc"
will print an entry for a directory called ./src/misc (if one exists). To ignore a
whole directory tree, use -prune rather than checking every file in the tree. For
example, to skip the directory src/emacs and all files and directories under it, and
print the names of the other files found, do something like this:

find . -path ./src/emacs -prune -o -print

From Findutils manual

— Action: -exec command ;
This insecure variant of the -execdir action is specified by
POSIX. The main difference is that the command is executed in the
directory from which find was invoked, meaning that {} is
expanded to a relative path starting with the name of one of the
starting directories, rather than just the basename of the matched
file.

While some implementations of find replace the {} only where
it appears on its own in an argument, GNU find replaces {}
wherever it appears.

And

For example, to compare each C header file in or below the current
directory with the file /tmp/master:

      find . -name '*.h' -execdir diff -u '{}' /tmp/master ';'

Best Answer

-path works exactly like -name, but applies the pattern to the entire pathname of the file being examined, instead of to the last component.

-prune forbids descending below the found file, in case it was a directory.

Putting it all together, the command

find $HOME -path $HOME/$dir_name -prune -o -name "*$file_suffix" -exec cp {} $HOME/$dir_name/ \;
  1. Starts looking for files in $HOME.
  2. If it finds a file matching $HOME/$dir_name it won't go below it ("prunes" the subdirectory).
  3. Otherwise (-o) if it finds a file matching *$file_suffix copies it into $HOME/$dir_name/.

The idea seems to be make a backup of some of the contents of $HOME in a subdirectory of $HOME. The parts with -prune is obviously necessary in order to avoid making backups of backups...

Related Question