Bash – How to get the exit code of commands started by find

bashcommand lineexit-statusfindshell

I am using "find" in a Travis-CI to check a particular file type with a program. (To be exact, it is a shellcheck check.)

However, when using find the exit codes of the command(s)/subshells executed by it are naturally discarded, as they are not passed to the "main script".

As an example this is a find command:

find . -type f -iname "*.sh" -exec sh ./testScripts.sh "{}" \;

./testScripts.sh may exit with 0 or >= 1, depending on the test result.

The testScripts.sh exits properly with the correct exit code, but due to find the exit code of the command is always "0". All I want is, that if one file/execution errors, this error is "propagated" up to Travis-CI.

How can I accomplish this?

Best Answer

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, then find will eventually do so as well, but this does not cause find to exit early.


Regarding the questions in comment:

  1. for n; do ... ; done looks weird but makes sense when you realize that without anything to iterate over, the for loop will iterate over "$@" implicitly.

  2. The trailing sh at the end will be placed in $0 of the sh -c shell. The {} will be substituted by a number of pathnames. Without sh 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 the sh -c shell).

Related Question