这是的限制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
并在Shell中使用递归glob:**/
表示子目录的任何深度。这需要bash版本4或更高版本;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,则递归globing可以立即使用,没有任何麻烦。Zsh在OSX / macOS上默认可用。在zsh中,您可以编写
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 {}
一次执行将失败。知道为什么吗?