Say I do:
find <paths> -exec cmd '{}' \; -printf <format>;
Where:
-exec cmd '{}'
prints exactly one line.-printf <format>
prints exactly one line.Is the ordering of the output guaranteed, to be interleaved as follows?
exec line
printf line
exec line
printf line
exec line
printf line
...
That is:
find
guarantee that the -exec;
and printf
tests not be reordered?find
guarantee that the individual tests not be batched, so I won't have a run of -exec;
output followed by a run of -printf
output?The same question applies to the opposite order, with the output correspondingly adjusted:
find <paths> -printf <format> -exec cmd '{}' \;;
The manual does have the following to say:
GNU find
searches the directory tree rooted at each given starting-point
by evaluating the given expression from left to right, according
to the rules of precedence (see section OPERATORS), until the
outcome is known (the left hand side is false for and operations,
true for or), at which point find moves on to the next file name.
-Olevel
Enables query optimisation. The find program reorders
tests to speed up execution while preserving the overall
effect; that is, predicates with side effects are not
reordered relative to each other. The optimisations
performed at each optimisation level are as follows.
0 Equivalent to optimisation level 1.
1 This is the default optimisation level and
corresponds to the traditional behaviour.
Expressions are reordered so that tests based only
on the names of files (for example -name and
-regex) are performed first.
The first part seems to rule out batching and I assume that -exec;
and -printf
are considered to have side-effects, but nonetheless I would like explicit confirmation despite all my testing.
Say I do:
find <paths> -exec cmd '{}' \; -printf <format>;
Where:
-exec cmd '{}'
prints exactly one line.-printf <format>
prints exactly one line.Is the ordering of the output guaranteed, to be interleaved as follows?
exec line
printf line
exec line
printf line
exec line
printf line
...
That is:
find
guarantee that the -exec;
and printf
tests not be reordered?find
guarantee that the individual tests not be batched, so I won't have a run of -exec;
output followed by a run of -printf
output?The same question applies to the opposite order, with the output correspondingly adjusted:
find <paths> -printf <format> -exec cmd '{}' \;;
The manual does have the following to say:
GNU find
searches the directory tree rooted at each given starting-point
by evaluating the given expression from left to right, according
to the rules of precedence (see section OPERATORS), until the
outcome is known (the left hand side is false for and operations,
true for or), at which point find moves on to the next file name.
-Olevel
Enables query optimisation. The find program reorders
tests to speed up execution while preserving the overall
effect; that is, predicates with side effects are not
reordered relative to each other. The optimisations
performed at each optimisation level are as follows.
0 Equivalent to optimisation level 1.
1 This is the default optimisation level and
corresponds to the traditional behaviour.
Expressions are reordered so that tests based only
on the names of files (for example -name and
-regex) are performed first.
The first part seems to rule out batching and I assume that -exec;
and -printf
are considered to have side-effects, but nonetheless I would like explicit confirmation despite all my testing.
Is the ordering of the output guaranteed, to be interleaved as follows?
For GNU find
, the manual specifies:
GNU
find
searches the directory tree rooted at each given starting-point by evaluating the given expression from left to right, according to the rules of precedence [...] until the outcome is known (the left hand side is false forand
operations, true foror
), at which pointfind
moves on to the next file name.
That wording is a bit awkward, but it nevertheless conveys that
find
command is fully evaluated for each file considered before it is evaluated for the next file, one file at a time. Thus, find
will not gang together multiple executions of the -exec
or of the -printf
.-exec
will be performed first.-exec
and -printf
operands are joined by an implicit and
operator, so the exit status of the -exec
'd command matters, because it determines whether the -exec
evaluates to true (status 0) or false (any other exit status). If that command ever exits with non-zero status then the -printf
will not be evaluated for that file.Thus, in GNU find
, the -exec
and -printf
are guaranteed to be evaluated in interleaved fashion, exec
first, corresponding to the output example, provided that the -exec
's command always terminates with status 0. I'll omit the details, but the same applies to POSIX find
.
Edit: Since you mention test optimization in the question, the point and effect of GNU find
's optimizations is to speed overall execution of find without changing the observable behavior, which definitely includes the order of any output produced by the evaluation of the operands of the find
expression. This is essentially the same "as if" rule that commonly applies to optimization: the observable behavior is as if no optimization were performed, except that it may be produced faster. The manual excerpt you present goes on to specify that it is the evaluation of tests based only on file name that may be done early. That should be read exclusively: optimization will reorder only name-based tests relative to other operands of the expression.
It may be of interest to you that neither POSIX nor GNU explicitly specifies that the output associated with evaluating those operands will be emitted in the same order that they are evaluated, so the output order is not guaranteed in that sense. Nevertheless, it is indeed the expected, well known, and reliable behavior of all find
implementations I know that the output associated with evaluating operands is indeed written in the same order that the operands are evaluated.
If you are so concerned with the order, and as the standards don't specify it, do it yourself
#! /bin/bash
# before
f="$1"
printf '%s\n' "$f"; cmd "$f"
or
#! /bin/bash
# after
f="$1"
cmd "$f" && printf '%s\n' "$f"
so
find <paths> -exec before '{}' \;
and
find <paths> -exec after '{}' \;
will behave as you expect.
find
, and-printf
is a GNU extension. Are you then asking specifically about the GNU implementation? – John Bollinger Commented Jan 12 at 20:41-print
. – user19087 Commented Jan 13 at 2:12find
found on the major Linux distributions: Arch, Nix, Fedora, Ubuntu, etc. – user19087 Commented Jan 13 at 2:13-exec
will always return true (0). – user19087 Commented Jan 13 at 2:18