如果发生错误,则使“find”返回非零退出代码

如果发生错误,则使“find”返回非零退出代码

为什么我会看到以下内容:

$ find  -not -exec bash -c 'foo' \; -quit
bash: foo: command not found
$ echo $?
0

这是我正在使用的实际脚本的简化版本,我将其发布在问题末尾(如果您真的想知道)。

所以问题是如何使用一堆查找结果find执行 shell并在第一个失败时退出exec bash -c还返回一个非零退出代码,我可以稍后在脚本中检查它?

*实际脚本*

#!/usr/bin/env bash
find path-a path-b path-c \
  -iname build.xml -not -exec bash -c 'echo -n "building {} ..." && ant -f {} build && echo "success" || (echo "failure" && exit 1)' \; -quit
RESULT=$?
echo "result was $RESULT"

答案1

这可以做到这一点:

#!/bin/bash
RESULT=0
while IFS= read -r -u3 -d $'\0' file; do
        echo -n "building $file ..."
        ant -f "$file" build &&
           echo "success" ||
           { echo "failure" ; RESULT=1 ; break; }
done 3< <(find path-a path-b path-c  -print0)

echo "result was $RESULT"

请注意,它findbash循环混合,如图所示这里

它不使用$?而是直接使用变量$RESULT

如果一切顺利$RESULT则为 0,否则为 1。一旦遇到错误,循环就会中断。

它应该能够安全地抵御恶意文件名(因为使用了-print0)。

答案2

如果您使用 find 命令,则在设置退出代码时会遇到困难。那是因为你有两种类型的输入(暂时忘记选项)和两种类型的工作:

  1. 您要查找的文件的路径。例如,如果您这样做,您可能不会希望因错误而退出find /mnt/log/storage/place -type f -mtime +7 -print。您的日志存储中可能存在小于 7 天的文件,因此跳过它们并不是错误 - 这就是您的意图。如果您/mnt/log/storage/place根本无法进入该路径,那将是一个错误。
  2. 控制 find 操作的表达式。表达式中的元素要么为真,要么为假。出于 的目的-exec,如果正在运行的命令返回 0,则为 true;如果返回非零,则为 false。更改 的行为-exec将使其在 find 中的所有其他表达式元素中独一无二,并且可能会破坏世界上许多现有的脚本。

因此,对于您的问题的另一个解决方案:您可以执行类似于 LatinSuDwhile循环的操作 - 您可以从变量检查命令的状态 - 但更简单:

errorout=$(find /tmp -type f \( -exec bash -c '/tmp/doit 1>/tmp/stdoutfile' \; -o -quit \) 2>&1 )

如果脚本/tmp/doit不可执行或生成到 stderr 的输出,则 errorout 变量将被填充。测试错误并做出如下反应:

[ -n "$errorout" ] || { echo 'Oh no- an error from find!'; /do/something/else; }

对于单行,你可以这样做:

errorout=$(find /tmp -type f \( -exec bash -c '/bin/false || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

替换/bin/false为您选择的命令。您可以执行这样的命令列表:

errorout=$(find /tmp -type f \( -exec bash -c '{ command1 && command2 && command3; } || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

如果您不想在列表中的命令第一次失败时立即退出:

errorout=$(find /tmp -type f \( -exec bash -c '{ command1; command2; command3; } || { echo "error" 1>&2; exit 1; }' \; -o -quit \) 2>&1 )

...不要忘记命令字符串中右大括号之前的分号。

相关内容