Это ограничение 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 {}
как выполняется один раз и завершается ошибкой. Есть идеи почему?{}
внутриbash -c
. Это берет имя файла и вставляет его непосредственно в команду оболочки. Если имя файла содержит символы, которые имеют особое значение в оболочке, например пробелы, оболочка интерпретирует эти специальные символы как таковые. Если вам нужна оболочка, передайте{}
в качестве отдельного аргумента, напримерbash -c 'foo "$0"' {}
(также обратите внимание на двойные кавычки$0
).find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
find . -print0 | xargs -0 -n1 invalid_command
). Это останавливается на первой ошибки правильно:find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}
. Большой! Но тот же подход не работает сbash -c
(выше). Единственная разница между этими двумяbash -c
.Я могу использовать это вместо:
источник
xargs
это один из вариантов. Тем не менее, это на самом деле тривиально легко сделать этоfind
, используя+
вместо\;
Из документации POSIX :
источник