「file」コマンドの出力を解析して、「find」で生成されたファイルをフィルタリングします。

「file」コマンドの出力を解析して、「find」で生成されたファイルをフィルタリングします。

node_modules私はnode.jsフォルダの内容やPythonのvirtualenv基本的な依存関係を調べるためのクイックツールを書いています。これを素早く最初の近似で次のコマンドを作成しました。

find . | xargs file | awk '/C source/ {print $1} /ELF/ {print $1}'

偽の肯定は許可されますが、偽の否定は許可されません(たとえば、ファイルに文字通り文字列が含まれているか、ELF疑わしいとマークされる可能性があります)。ただし、このスクリプトは長いファイル名(分割されているため)とスペースを含むファイルC sourceでも失敗する可能性があります。xargsスペースに分割されます)と改行を含むファイル名(findがパスを区切るために改行を使用するため)。

find出力file {}(おそらく出力からパスを完全に削除するためにいくつかの追加オプションを使用file)が特定の正規表現と一致することを確認して生成されたパスをフィルタリングする方法はありますか?

答え1

悟りを達成する重要な要素はfind次のとおりです。

find仕事はファイルを見つけるのではなく、式を評価することです。はい、findもちろんファイルを見つけることができますが、実際には副作用だけです。

- Unix電動工具

この問題には、もう1つのアプローチがあります(Unix Power Toolsにも説明されています)。"-execを使用したカスタムテストの作成"):

find . -type f -exec sh -c 'file -b "$1" | grep -iqE "^ELF|^C source"' sh {} \; -print

このフィルタリング方法は、ファイル名を印刷する以外の目的で使用できるため、知っておくことをお勧めします。-print演算子を他の演算子を含む他の演算子-execに変更し、必要に応じて実行できます。


そこはいこのコマンドのパフォーマンス障害(次にも表示されます)もう一つの答え\;)、私たちは使用していないので、+各ファイルに対してシェルを生成します。一度に複数のファイルをコマンド+に渡してループを使用して処理すると、パフォーマンスが大幅に向上します。shfor

find . -exec sh -c 'for f do file -b "$f" | grep -qE "^ELF|^C source" && printf %s\\n "$f"; done' sh {} +

次の2つのコマンドを実行し、出力を比較して直接比較内容を確認できますtime

time find . -exec sh -c 'for f do file -b "$f" | grep -qE "^ELF|^C source" && printf %s\\n "$f"; done' sh {} +
time find . -exec sh -c 'file -b "$1" | grep -qE "^ELF|^C source" && printf %s\\n "$1"' sh {} \;

しかし、実際のポイントは次のとおりです。

forから出力されるファイルのリストに対してシェルループを実行しないでくださいfindfind代わりに、演算子を使用して各ファイルで実行する必要があるタスクを直接実行できます-exec含めるシェルforループ以内に1つのコマンドをfind実行するだけです。

いくつかの追加理由:

答え2

最も簡単な方法は、各ファイルに対して小さなスクリプトを実行し、短いパターン出力を確認し、出力が一致したりパスを印刷したりすると、パスがfilefile渡さELFれるC sourceことです$0

find . -type f -exec sh -c \
    'file -b "$0" | grep -q "^ELF\|^C source" && printf %s\\n "$0"' {} \;

この計画は、元の計画と比較して次の利点があります。

-type f出力に依存するのではなく、すぐにディレクトリをフィルタリングします。file

パラメータを渡すと、{}ファイル名のスペースや改行に関連する問題を回避できます。

関連情報