私は、bash の「find」を使用して、.log ファイルを含むすべてのフォルダーを処理し、そのサイズを取得しようとしています。しかし、ワイルドカードは期待どおりに機能しません。何も返されません。
find . -type d -exec test -e '{}/*.log' \; -exec du -d0 '{}' \;
*.log
ただし、を に置き換えるとfoo.log
、そのファイル名を含むディレクトリに対して期待どおりに動作します。
いくつかの同様の SE 投稿に基づいて、次のことを試しました。
find . -type d -exec bash -c 'test -e "{}/*.log"' \; -exec du -d0 '{}' \;
find . -type d -exec bash -c 'test -e "$1/*.log"' '{}' \; -exec du -d0 '{}' \;
しかし、それらはそれほどうまく機能しません。
答え1
のようfind … -exec test -e '{}/*.log'
な文字列を に渡すと、something/*.log
test
*
リテラルどちらのツールもこれをワイルドカードとして扱いません。 の実装によっては、これが引数の一部である場合(引数全体ではなく)find
も展開されません。{}
{}
後で試すものの 1 つは、{}
シェル コードに埋め込まれます。{}
シェルコードに埋め込まないこの問題に関しては、もう1つの試みの方が良いでしょう。解決に近づいています。ちょっと仕事:
# still flawed though
find . -type d -exec bash -c 'test -e "$1/"*.log' bash '{}' \; -exec du -d0 '{}' \;
見るの2番目のshは何ですかsh -c 'some shell code' sh
?ただし、主な「修正」は、シェル コードでアスタリスクを引用符で囲まないことです。この方法では、内部シェルではワイルドカードになります (ただし、外部シェルではワイルドカードにならず、適切に単一引用符で囲まれます)。問題は、*.log
複数の単語に展開される可能性があることです (一致するファイルが多数ある場合)。この場合、test
呼び出しが中断されます。
次のコードは*.log
ファイルのあるディレクトリを検索します。
find . -type d -exec sh -c '
for f in "$1/"*.log; do test -e "$f" && exit 0; done; exit 1
' sh {} \; -print
このコードは移植可能です。 inner は必要なくbash
、sh
より高速になるはずです。必要に応じ-print
て に置き換えてください。-exec du …
exit 0
これは、一致するファイル¹の存在が確認されるとすぐに、内部シェルから成功 ( ) を返すことによって機能しますtest
。まだテストされていない一致するファイル (存在する場合) は無駄にテストされず、これにより時間が節約されます。一致しない場合は、パターンはリテラルのままで失敗test
し、シェル全体が失敗して終了します ( exit 1
)。-exec
もテストであるため、-print
(または-exec du …
そこに置いたもの) が実行されるかどうかに影響することに注意してください。
別のアプローチとしては、find
一致するファイルを見つけるようにする
find . -name '*.log' … -print
そして、その出力を解析してディレクトリ名を分離し、最終的に で使用しますxargs
。du
ディレクトリは複数回出現する可能性があり、パス名内の改行には移植性のないコード ( から始まる) が必要になります-print0
。これは不必要に複雑になると思います。ディレクトリを検索する方が優れているようです。
¹test -e
ファイルがあるかどうかはメモで確認できますディレクトリなど通常のファイルの存在を確認するには を使用しますtest -f
。
答え2
ログ ファイルを検索/スキャンして、一意のディレクトリ名を収集する方が簡単になります。
このfind
コマンドは、ディレクトリを抽出し、uniq
重複を削除して追加します。/フラグは、改行/スペース/引用符を含むパス名が完璧に解析されるようにするのに役立ちます-z
。-0
find . -type f -name \*.log -exec dirname -z {} \+ | uniq -z | xargs -0 -r du -d0
| sort -rn |head
最大のディスク使用量を検索する場合に追加します。