如果-exec失败,如何使查找失败?


29

当我在外壳程序(非空目录)中运行此命令时:

find . -exec invalid_command_here {} \;

我得到这个:

find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory

(每个文件等等)

我需要find在第一个错误后失败。有什么办法可以使它正常工作吗?我不能使用xargs,因为我的路径中有空格,但是我需要调用此脚本的脚本来返回错误代码。

Answers:


34

这是的限制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 {}一次执行将失败。知道为什么吗?
DKroot

@DKroot请勿{}在内部使用bash -c。这将获取文件名并将其直接插入到shell命令中。如果文件名包含在shell中具有特殊含义的字符(例如空格),则shell会这样解释这些特殊字符。如果需要外壳,则将其{}作为一个单独的参数传递,例如bash -c 'foo "$0"' {}(也请注意在双引号周围$0)。
吉尔(Gilles)“所以,别再邪恶了”

好吧,除了引用问题,为什么以下情况不会因第一个错误而停止?find . -name '*' -print0 | xargs -0 -n 1 -I '{}' bash -c 'foo "$0"' {}
DKroot

@DKroot为什么会因错误而停止?xargs始终在所有项目上运行命令。
吉尔斯(Gilles)'所以

我正在尝试使用以下答案:xargs(find . -print0 | xargs -0 -n1 invalid_command)方法。这会在第一个错误上正确停止:find . -name '*' -print0 | xargs -0 -n 1 -I '{}' foo {}。大!但是,相同的方法不适用于bash -c(上面)。两者之间的唯一区别是bash -c
DKroot


4

xargs是一种选择。但是,find通过使用+代替\;

-exec  utility_name  [argument ...]   {} +

POSIX文档中

如果主表达式用加号标点,则主表达式应始终被评估为true,并且为其求值的路径名应汇总为集合。对于每组聚合路径名,应一次调用实用程序Utility_name。每次调用应在集合中的最后一个路径名聚集之后开始,并且应在find实用程序退出之前和为此主集合的下一个集合中的第一个路径名(如果有)聚集之前完成,但是在其他方面未指定在其他原色的评估之前,之中或之后发生。如果任何调用返回非零值作为退出状态,则查找实用程序应返回非零退出状态。仅包含两个字符“ {}”的参数应由一组聚合的路径名代替,每个路径名均作为一个单独的参数传递给调用的实用程序,其顺序与聚合的顺序相同。两个或更多路径名的任何集合的大小应受到限制,以使实用程序的执行不会导致超过系统的{ARG_MAX}限制。如果存在多个仅包含两个字符“ {}”的参数,则行为未指定。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.