Это ограничение find
. Стандарт POSIX указывает, что возвращаемое состояние find
равно 0, если при обходе каталогов не произошла ошибка; статус возврата выполненных команд в него не входит.
Вы можете заставить команды записывать их статус в файл или в дескриптор:
find_status_file=$(mktemp findstatus)
: >"$find_status_file"
find … -exec sh -c 'trap "echo \$?" EXIT; invalid_command "$0"' {} \;
if [ -s "$find_status_file" ]; then
echo 1>&2 "An error occurred"
fi
rm -f "$find_status_file"
Как вы обнаружили , другой метод - использовать xargs. Эти xargs
команды всегда обрабатывает все файлы, но возвращает состояние 1 , если какой - либо из команд возвращает статус нуля.
find … -print0 | xargs -0 -n1 invalid_command
Еще один метод заключается в том, чтобы избегать find
и использовать рекурсивное сглаживание в оболочке: **/
означает любую глубину подкаталогов. Это требует версии 4 или выше bash; MacOS застрял на версии 3.x, поэтому вам придется установить его из коллекции портов. Используйте set -e
для остановки сценария в первой команде, возвращающей ненулевой статус.
shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done
Помните, что в bash 4.0 до 4.2 это работает, но проходит через символические ссылки на каталоги, что обычно нежелательно.
Если вы используете zsh вместо bash, рекурсивное сглаживание работает из коробки без ошибок. Zsh доступен по умолчанию в OSX / macOS. В зш можно просто написать
set -e
for x in **/*.xml; do invalid_command "$x"; done
xargs
Подход работает в целом , но как - то ломает наbash -c
команды. Например:find . -name '*.xml' -print0 | xargs -0 -n 1 -I '{}' bash -c "foo {}"
. Это выполняется несколько раз, тогдаfind . -name '2*.xml' -print0 | xargs -0 -n 1 -I '{}' foo {}
как выполняется один раз и завершается ошибкой. Есть идеи почему?