Preliminary note: the manual and your question uses command
to denote the command, but since POSIX defines an utility literally named command
, my answer will use cmmnd
.
If you want to actually run cmmnd
(s) and just count the number of invocations (to know it after find
finishes) then create a wrapper that does something you can count (e.g. prints to stderr, prints to a logfile, beeps) and eventually runs the cmmnd
. Example:
#!/bin/sh
echo "invoking cmmnd" >&2
cmmnd "$@"
Then use the wrapper
instead of the cmmnd
inside find
.
Note find
will use the /absolute/path/to/wrapper
while creating commands that are not too long; then the wrapper will use /absolute/path/to/cmmnd
. If the latter is longer then some command line(s) containing it may turn out to be too long anyway. So this approach is not as straightforward as we wish. You can extend the former path by supplying it to find
verbatim with additional slashes (e.g. /absolute/path/to/////wrapper
).
Now I assume you want to know the number before you decide to run cmmnd
(s). Like in a case where calling the cmmnd
twice is a bad thing (for whatever reason) and you want to make sure find
will run it exactly once.
The above wrapper with cmmnd "$@"
commented out can be used. Below are few other ideas (in the end not so different though).
Let's assume you want to do this:
find . -exec cmmnd … {} +
(where …
denotes constant arguments). Find out what the absolute path to cmmnd
really is. E.g. it can be /bin/cmmnd
. Then run something like this:
find . -exec /aaa/zzzzz … {} +
where /aaa/zzzzz
is a nonexistent command whose name is of the same length as /bin/cmmnd
. Now find
will build command lines with /aaa/zzzzz
that will be of the same length as command lines with /bin/cmmnd
would be. You will get
find: '/aaa/zzzzz': No such file or directory
one or more times. Count them to get the number you want. This simple approach:
find . -exec /aaa/zzzzz … {} + 2>&1 | wc -l
is not the best because find
may also print e.g. permission denied
for some files it encounters. But if you create /aaa/zzzzz
as a valid executable that prints exactly one line (it can be an empty line), then this should work:
find . -exec /aaa/zzzzz … {} + | wc -l
Another improvement is to name the tool /a
(instead of /aaa/zzzzz
), and call it as /////a
or /////////////////a
etc., depending on the length you need. Example:
find . -exec /////////a … {} + | wc -l
For completeness, this is what a
may look like:
#!/bin/sh
echo
It's almost like our wrapper without cmmnd "$@"
, it uses the stdout though.
Notes:
The exact number of /
characters is not critical. A mistake by few will not change the result drastically. If you need an estimate result, you can blindly use ///////////a
or so, unless the path to the cmmnd
is unusually long. Note that using exactly /a
will give you the lower bound.
In practice you often have other tests before -exec cmmnd … {} +
. If you replace cmmnd
with /////////a
or so, the other tests will still be performed. You should not omit them because they decide what pathnames get to -exec
in the first place. But if the tests do or change something, it may be that performing them without the cmmnd
is wrong.
E.g. you may want to delete files with -delete -exec cmmnd … {} +
, where cmmnd
generates a report on files that have been deleted. In this case using /////////a
will delete files without generating any report. So think before you act.
Make sure tests/actions/whatever other than -exec /////////a … {} +
print nothing to stdout. Or let /a
use some other channel.
Processing the given directory tree(s) and performing (other) tests may take a while even without cmmnd
(s).
+
is the extension that makes -exec run a list in a similar way toxargs
. With a plain{}
, the command does run once per filename. My Linux understandsgetconf ARG_MAX
and tells me2097152
. Yourcommand
could also be a script that chunks the initial arg-list and calls the final command multiple times with a more sensible arg-list, and could also handle Begin and End conditions.