4

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 ';'
  • Possible duplicate of find: prune does not ignore specified path – thecarpy Jul 7 '17 at 20:41
  • I think if anything it's a duplicate of find-path explained even if the answer at find:prune does not ignore specified path has an answer that seems to apply to this question. Maybe the find-path explained answers make sense to someone more experienced with scripting, but they don't help me. The answers present here make more sense to me so far, even though I'm just starting to look into them. – flerb Jul 7 '17 at 21:36
8

-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...

  • If I understand then: find will iterate through each and every directory in $HOME that it has permissions to go into, except $HOME/$dir_name, which it will not descend into (because the prune action will evaluate to true and the or will not be taken), searching for files that end with $file_suffix. Then as soon as it finds one, it will execute cp "found_file.sh" into $HOME/$dir_name ? Also, -path allows for a path to a file, and is useful when you want find to descend into directories and not just work in the current directory? – flerb Jul 7 '17 at 22:02
  • Your understanding is almost correct. -path works just as -name: it selects files. The difference is that -name matches a pattern to the file name, whereas -path matches a pattern to the full pathname. find always descends into subdirectories, unless prevented by -maxdepth or -prune etc. – AlexP Jul 7 '17 at 22:09
  • Oh! -path is being applied to $HOME/$dir_name -prune then, it's the order of commands that was messing me up, and -path is necessary for the prune command because it needs to match the full path of the pruned directory. – flerb Jul 7 '17 at 22:15
  • @Darren I'm not sure if that's quite accurate. -path $HOME/$dir_name is one action. It is a test that checks whether the path of the current file being examined matches whatever $HOME/$dir_name is. -prune is a separate action. I think the first sentence of your first comment accurately reflects how that works. – David Z Jul 8 '17 at 6:46
  • Would it be missing something to see it as a pipe? I swapped -prune with -print and think the flow is clear now : find $HOME | -path $HOME/$dir_name | -print – flerb Jul 8 '17 at 14:09
3

It is part of the find command, the -exec statement.

It allows you to interact with the file/directory found by the find command.

find $HOME -path $HOME/$dir_name -prune -o -name "*$file_suffix" -exec cp {} $HOME/$dir_name/ \;

find $HOME means find files/directories in $HOME

To understand -path <some_path>, see `find -path` explained

To understand -prune, see https://stackoverflow.com/questions/1489277/how-to-use-prune-option-of-find-in-sh

-o means OR, so -path <some_path> OR -name *$file_suffix

-exec means execute the command.

cp {} $HOME/$dir_name/ copy any files matching to $HOME/$dir_name/

\; means terminate the -exec command

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.