特定の場所に空のファイルがあるかどうかを調べ、見つかった場合は、電子メールを送信する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
内で行われます。プロセスの環境は親プロセスに再コピーされません。単に環境変数を設定して終了するシェルプロセスは、継続的な操作を完了しません。sh
find
一致するファイルがあるかどうかをテストするには、find
出力が空であるかどうかを単にテストします。空でないことを証明した後にファイルを削除するために長いファイルのリストを生成しないようにするには、find
まず出力を切り取ることができます。 GNU findには、-quit
単一の文字も表示するように簡単に知ることができる述語があります。次のコードスニペットにFLAG
一致するものがない場合、結果は空です。
FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)
次の変数はFLAG
0または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 globstar
Kshと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
}