find+execで変数を設定するには?

find+execで変数を設定するには?

特定の場所に空のファイルがあるかどうかを調べ、見つかった場合は、電子メールを送信するbashスクリプトを作成しようとしています。最初は「検索」と「メール」を組み合わせようと思っていましたが、その場所に空のファイルが複数ある場合は、不要なメールが複数送信されるので、探して設定する前にフラグを入れることを考えました。変数は以下で設定されます。 0から1までで、空のファイルがあるかどうかを確認するために検索が行われます。私が試したことは次のとおりです。

FLAG=0
find $LOCATION -size 0 -type f -exec sh -c 'export FLAG=1' \;
echo $FLAG

ところが問題は、その場所に空のファイルがあってもフラグ値が1に変わらないという点だ。私は何が間違っていましたか?

答え1

set -- "${LOCATION}/"*
while [ -s "$1" ] ; do shift ; done
[ -e "$1" ] && FLAG=1

シェル組み込みコマンドは、[ test ]ize演算子で使用できます-s。からman test

-s FILE

FILE存在し、サイズが0より大きい。

しかし、再帰的な検索ではこれは簡単ではありません。

findはい、しかし、ブール値を設定するのと同じように、単純な操作の場合、実際にはこの場合には適していません。ls再帰検索も同様にすばやく行うことができ、ファイルサイズをリストの最初のフィールドとして提供するように簡単に設定でき、1行に1つの項目のみを一覧表示することができます。再帰ファイルリストにサイズが0のファイルが含まれているかどうかに応じてシェル変数のブール値を設定する場合は、これがls最善の選択ですfind。これは状況を複雑にするだけです。興味のあるものはファイルの場所ではなく、ファイルのプロパティです。それがls光を発する場所であり、grep出力をpingすることは非常に簡単です。

これは簡単に行えます。

ls -1aqRsp "$LOCATION" 2>&1 | grep -qv "^ *[^0]\|/"
FLAG=$(($?==0))

これは、ファイルが次FLAGの場合にのみ設定されます。1隠された .dot埋め込みファイル -$LOCATIONそのサブディレクトリの1つに存在し、サイズが0です。それ以外の場合は$FLAGそうです0

答え2

findこれにより、新しいサブプロセスが分岐します-exec。どの子プロセスも親プロセスの環境を変更できません。

find問題のファイル名を収集してから、2番目のステップで目的の電子メールを生成することを検討できます。

find . -type f -size 0 -print >> /var/tmp/find.sz0
...

答え3

これは呼び出しインスタンスexport FLAG=1内で行われます。プロセスの環境は親プロセスに再コピーされません。単に環境変数を設定して終了するシェルプロセスは、継続的な操作を完了しません。shfind

一致するファイルがあるかどうかをテストするには、find出力が空であるかどうかを単にテストします。空でないことを証明した後にファイルを削除するために長いファイルのリストを生成しないようにするには、findまず出力を切り取ることができます。 GNU findには、-quit単一の文字も表示するように簡単に知ることができる述語があります。次のコードスニペットにFLAG一致するものがない場合、結果は空です。

FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)

次の変数はFLAG0または1に設定されます。

FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)
[ -n "$FLAG" ] || FLAG=0

移植性を維持するには、find印刷マッチングを実行して最初の行を維持するだけですfind信号パイプラインheadパイプの片側を閉じた後。

if [ -n "$(find "$LOCATION" -size 0 -type f -print | head -n 1 \;)" ]; then
  FLAG=1
else
  FLAG=0
fi

これが単なる例であり、より複雑な変数を設定する必要がある場合は、いくつかの可能なアプローチがあります。いくつかの一般的な事項に言及します。

Zshには次findの機能が組み込まれています。グローバル予選。次のコードスニペットはfiles一致するファイルのリストを設定しますfind $LOCATION -size 0 -type f

files=(**/*(.DL0))

set -o globstarKshとbashもそれぞれ使用され、有効になっている場合は再帰的なグローブを持ちますshopt -s globstar。しかし、bashがバージョン4.2に達すると、ディレクトリ**のシンボリックリンクに再帰するため、通常はお勧めできません。シェルで追加の処理を実行できます。

FIGNORE=         # include dot files in wildcard matches (the ksh way)
GLOBIGNORE=.:..  # include dot files in wildcard matches (the bash way)
for x in **/*; do
done

一致するファイル名に改行が含まれていない場合は、出力を改行区切りfindリストに解析できます。

find "$LOCATION" -size 0 -type f ! -name '*
*' -print | {
  while read -r empty_file; do
  done
}

関連情報