Rate this page

Flattr this

Act on all files in a directory tree using find

Tested on

Debian (Etch, Lenny, Squeeze)
Fedora (14)
Ubuntu (Hardy, Intrepid, Jaunty, Karmic, Lucid, Maverick, Natty, Precise, Trusty)

Objective

To perform a given action on all files in a given directory tree

Scenario

The path ~/src/foo-1.0.0/ is the root of a directory tree which contains files of several different types, including a number of Perl scripts. You wish to ensure that these scripts have a file mode of 755 (writable by their owner, readable or executable by anyone). The scripts may be distinguished from the other files by the fact that their names end in the suffix .pl.

Method

List the files to be acted upon using find. Use the -execdir option to execute the required command:

find ~/src/foo-1.0.0 -name "*.pl" -type f -execdir chmod 755 {} \;

The first argument to find is the root of the directory tree to be searched.

The option -name precedes a glob pattern which in this case restricts the search to files with the extension .pl. The pattern must be placed in quotes, otherwise there is a risk that it will be expanded by the shell before being passed to find.

The option -type f specifies that only regular files are to be matched (as opposed to, for example, directories). By default find will match everything that it finds in the given directory tree, but this is rarely the desired behaviour when passing the pathnames to a command.

The option -execdir specifies the command to be executed. The symbol {} acts as a placeholder for the pathname to be acted upon (and may be used more than once if necessary). The components of the command must be passed as separate arguments, not as a monolithic string. The semicolon (which should normally be escaped, as above) terminates the command.

Testing

Commands of the type described here can damage a large number of files in a very short space of time if you make a mistake. You may therefore wish to perform a dry run first, to inspect the commands that would be executed without actually executing them. This can be done by inserting an echo command after the -execdir option:

find ~/src/foo-1.0.0 -name "*.pl" -type f -execdir echo chmod 755 {} \;

This technique will not work if the command contains any redirections, but you can work around that limitation by temporarily replacing the redirection token with some other string that has no special meaning to the shell.

It may be helpful to use the pwd to display the directory in which each command will be executed. This requires some trickery to prevent pwd from being executed prematurely:

find ~/src/foo-1.0.0 -name "*.pl" -type f -execdir sh -c "echo \`pwd\` chmod 755 {}" \;

(Note that spaces and other special characters will not be escaped in the commands as listed.)

Troubleshooting

An effective strategy for troubleshooting is to first check that the correct pathnames are being selected, then that the correct commands are being executed.

To check which pathnames are selected, execute the find command without the -execdir option:

find ~/src/foo-1.0.0 -name "*.pl" -type f

An easy mistake to make here is not putting the patten in quotation marks. If you don't, and there are one or more files in the current working directory that match the pattern, then the pattern will be expanded by the shell. If the pattern expands to exactly one pathname then the find command will appear to work, but will not necessarily have acted upon all the files it should have done.

Note that long options to find being with a single hyphen (not the double hyphen required for most other commands).

If the pathnames are correct then the error must lie in the commands that are executed. These can be inspected using the dry-run technique described above. Points to check are that:

See also

Tags: shell