How to get the exit code of commands started by find?
Using Stephen Kitt's suggestion in comments:
find . -type f -iname "*.sh" -exec sh -c 'for n; do ./testScripts.sh "$n" || exit 1; done' sh {} +
This will cause the sh -c
script to exit with a non-zero exit status as soon as testScript.sh
does. This means that find
will also exit with a non-zero exit status:
If terminated by a plus sign, the pathnames for which the primary is evaluated are aggregated into sets, and utility will be invoked once per set, similar to
xargs(1)
. If any invocation exits with a non-zero exit status, thenfind
will eventually do so as well, but this does not causefind
to exit early.
Regarding the questions in comment:
for n; do ... ; done
looks weird but makes sense when you realize that without anything to iterate over, thefor
loop will iterate over"$@"
implicitly.The trailing
sh
at the end will be placed in$0
of thesh -c
shell. The{}
will be substituted by a number of pathnames. Withoutsh
there, the first pathname would end up in$0
and would not be picked up by the loop, since it's not in$@
.$0
usually contains the name of the current interpreter (it will be used in error message produced by thesh -c
shell).
xargs
will exit with an exit status between 1 and 125 (123 with GNU xargs
), if any of the command fails, and will abort if any fails with a 255 status.
To use xargs
reliably on the output of find
(with -print0
) and preserve the command's stdin, you'd need GNU xargs
though. So, with GNU xargs
and a shell with support for process substitution like ksh
, zsh
or bash
:
xargs -n1 -r0a <(find . -type f -iname '*.sh' -print0) sh ./testScripts.sh
Or to abort at the first failing one:
xargs -r0a <(find . -type f -iname '*.sh' -print0) sh -c '
for file do
sh ./testScripts.sh "$file" || exit 255
done' sh
You can also abort find
upon the first error with (POSIX code):
find . -type f -name '*.[sS][hH]' -exec sh -c '
for file do
if ! sh ./testScripts.sh "$file"; then
kill -s PIPE "$PPID"
exit 1
fi
done' sh {} +
(using SIGPIPE as a less noisy signal with some shells like bash
). That will cause find
to be killed and so return with a non-zero exit status.
To get the exact value of the exit status of the (here last) failing commmand, with zsh
or bash
, you can also do:
ret=0
while IFS= read -rd '' -u3 file; do
sh ./testScripts.sh "$file" 3<&- || ret=$?
done 3< <(find . -type f -iname '*.sh' -print0)
Though with zsh
, you don't even need find
for that:
set -o extendedglob
ret=0
for file (./**/*(#i).sh(D.)) {
./testScripts.sh $file || ret=$?
}