1. Introduction
find is a powerful command to search for files on our disk matching the given criteria. It allows us to run a command on the matching files. In this tutorial, we’ll learn how to run a sequence of commands on the matching files.
There are three ways to run multiple commands:
- multiple -exec options
- using boolean expression
- combined script
2. Basic find Command
Let’s use the following basic find command to learn all three methods:
$ pwd
/usr/include
$ find . -name "sysexits.h"
./sysexits.h
Here, we use the find command to find all files which match the name “sysexits.h“.
Next, let’s use two more Bash commands, wc and file, on the above output of find:
$ pwd
/usr/include
$ wc ./sysexits.h
114 876 5232 ./sysexits.h
$ file ./sysexits.h
./sysexits.h: C source, ASCII text
wc prints the word count of the file. file prints the type of the file. In the examples below, we’ll run both these commands using the find command’s -exec option.
3. Multiple -exec Options
The find command allows us to run the commands in sequence by using the –exec option multiple times in the command line:
$ find . -name "sysexit*.h" -exec wc {} \; -exec file {} \;
114 876 5232 ./sysexits.h
./sysexits.h: C source, ASCII text
The command find sends the result to the child commands. The string ‘*{}’* is replaced with the result of the find command. As illustrated above, we run two commands in sequence, and we see the output of both commands on two separate lines. The file command is run only if the first command is successful. If the first command fails for some reason, then the subsequent command isn’t executed:
$ find . -name "sysexit*.h" -exec wc cc \; -exec file {} \;
wc: cc: No such file or directory
As the command wc failed to run on a non-existent file, the following command file wasn’t executed.
4. Using Boolean Expressions
The find command also has the option to evaluate the sequence of boolean expressions. This allows us to run all the commands irrespective of the result of the commands:
$ find . -name "sysexits.h" \( -exec wc {} \; -o -true \) -exec file {} \;
114 876 5232 ./sysexits.h
./sysexits.h: C source, ASCII text
$ find . -name "sysexits.h" \( -exec wc cc \; -o -true \) -exec file {} \;
wc: cc: No such file or directory
./sysexits.h: C source, ASCII text
In the above example, we ran the command two times. The first boolean or expression \( -exec wc {} \; -o -true \) evaluates to true irrespective of the result of the wc command. We had valid input to the wc command in the first instance. In the second, we gave invalid input to the wc command. In both cases, find executes the file command.
5. Combined Script
We can also combine all the commands as input to the Bash shell in the find command:
$ find . -name "sysexits.h" -exec bash -c 'wc "$0"; file "$0"' {} \;
114 876 5232 ./sysexits.h
./sysexits.h: C source, ASCII text
In the above example, we run Bash as a shell and pass the sequence of commands to it. One important concept to note is the usage of “$0” in the script. This is because the result of find is passed as a parameter to the inline script.
6. Conclusion
In this article, we learned three ways of executing a sequence of commands on the output of the find command. Using the -exec option multiple times is a simple way of using it. On the other hand, the boolean expression allows an advanced use case of executing the commands conditionally. If there are more than a few commands, then it is preferable to use the combined script.