エラーが発生すると、 'find'はゼロ以外の終了コードを返します。

エラーが発生すると、 'find'はゼロ以外の終了コードを返します。

なぜ以下が表示されますか?

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

これは私が使っている実際のスクリプトの単純化されたバージョンです。 (本当に知りたい場合)質問の最後に投稿します。

したがって、問題は、find複数の検索結果でシェルを実行し、最初の結果が失敗したときに終了する方法です。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"

図のようにループfindと混在しています。bashここ

$?変数を直接使用しません$RESULT

$RESULTすべてがうまくいけば0、そうでなければ1です。エラーが発生すると、ループは中断されます。

(使用のため-print0)悪意のあるファイル名から安全でなければなりません。

答え2

find コマンドを使用すると、終了コードを設定するのが難しくなります。その理由は、2種類の入力(今はオプションを忘れてください)と2種類の種類があるからです。

  1. 探しているファイルへのパス。たとえば、これを行うと、エラーが発生して終了することを望まないでしょうfind /mnt/log/storage/place -type f -mtime +7 -print。ログストアには7日以上経過していないファイルがある可能性があるため、ファイルをスキップすることはエラーではありません。これはあなたの意図です。/mnt/log/storage/placeパスにまったく入らない場合はバグです。
  2. 検索操作を制御する表現式です。式の要素はtrueまたはfalseです。この目的に応じて、-exec実行中のコマンドが0を返す場合はtrue、0以外の値を返す場合はfalseです。変更された動作により-exec、findの他のすべての表現要素の中で一意になり、世界中の多くの既存のスクリプトが中断される可能性が高くなります。

したがって、問題に対する別の解決策:whileLatinSuDループと同様の操作を実行できます。変数でコマンドの状態を確認できますが、より簡単です。

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; }

1行に対して次のことができます。

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 )

...コマンド文字列で閉じる中括弧の前にあるセミコロンを忘れないでください。

関連情報