Saturday, June 28, 2014

Grouping -exec commands using the find command in shell

I just found out how to group commands that are executed on filenames found by the command line tool find.
The common syntax is:

find <path>[options] -exec command1 \; -exec command2 \;

where command2 is only executed if command1 exits with a zero return value.
While I was using this quite a lot, the actual syntax was not clear to me up to just a couple of minutes ago:

-exec is a find expression and expressions are separated by operators, where a missing operator is interpreted as -a (AND). Furthermore, expressions can be grouped by parentheses, which is especially useful when you want to perform some actions only on some files, but more actions on all of them afterwards.

As an example, take a directory tree with the following structure:
$ find .
.
./arch
./arch/install.log

Then, the following command
$ find . \( \( -exec test -d {} \; -a -exec sh -c 'echo {}; exit 1' \; \) , -exec echo {} \; \)
.
.
./arch
./arch
./arch/install.log

prints every path found by find, and prints it a second time if it is a directory, hence './arch' and '.' are printed twice, respectively, while './arch/install.log' is printed only once.

Step by step, if
-exec test -d {} \;
returns false,
-exec sh -c 'echo {}; exit 1' \;
will not be executed, as both are seperated by the AND (-a) operator. The grouped expression, indicated by parentheses, always returns false, as the second command contains 'exit 1'. Nevertheless,
 -exec echo {} \;
will always be executed, as two expressions separated by the ',' operator will always be executed, returning the outcome of the second expression.

For more information, read the find man pages, in particular sections EXPRESSIONS, ACTIONS and OPERATORS.

No comments:

Post a Comment