web-dev-qa-db-ja.com

findを使用して見つかったファイルのコンテンツを1つのファイルに分類するにはどうすればよいですか?

貴重なデータを保持するパーティションを再フォーマットすることで、痛むところ(本当に悪い)に自分を撃つことができました。もちろんそれは意図的なものではありませんでしたが、起こりました。

しかし、私はtestdiskphotorecを使用してほとんどのデータを回復することができました。これで、すべてのデータがほぼ25,000のディレクトリに分散されました。ほとんどのファイルは.txtファイルで、残りは画像ファイルです。各ディレクトリには300を超える.txtファイルがあります。

grepまたはfindを使用して、.txtファイルから特定の文字列を抽出し、ファイルに出力できます。たとえば、次の行は、データが復元されたファイルにあることを確認するために使用しました。

find ./recup*/ -name '*.txt' -print | xargs grep -i "searchPattern"

「searchPattern」をファイルに出力することはできますが、そのパターンが得られるだけです。これが私が本当に達成したいことです:

すべてのファイルを調べ、特定の文字列を探します。その文字列がファイルで見つかった場合、そのファイルのすべての内容を出力ファイルにcatします。パターンが複数のファイルで見つかった場合は、後続のファイルの内容をその出力ファイルに追加します。検索しているパターンを出力したくないだけで、パターンが見つかったファイルのすべての内容を出力したいことに注意してください。

これは可能だと思いますが、特定のパターンをそこからgrepした後で、ファイルのすべての内容を取得する方法がわかりません。

11
Ami

私があなたの目標を正しく理解していれば、以下はあなたが望むことをします:

find ./recup*/ -name '*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

これにより、*.txt内のすべての./recup*/ファイルが検索され、各ファイルがsearchPatternと一致する場合は、catに対してテストされます。すべてのcatedファイルの出力はoutputfile.txtに送信されます。

各パターンと出力ファイルについて繰り返します。


./recup*に一致するディレクトリが非常に多い場合は、argument list too long errorになる可能性があります。これを回避する簡単な方法は、代わりに次のようなことをすることです:

find ./ -mindepth 2 -path './recup*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

これは完全パスと一致します。したがって、./recup01234/foo/bar.txtが一致します。 -mindepth 2は、./recup.txt、または./recup0.txtと一致しないようにするためのものです。

10
Patrick

パターンを出力するのではなく、grepで「-l」を使用してファイル名を出力し、それをcatへの入力として使用します。

find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern" | xargs cat

または

cat $( find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern")

残りの詳細を記入できると思います。ところで、ファイル名にスペースやその他の奇妙な文字が含まれている可能性がある場合(この特定のケースではそうではないが、将来の目的のため)、検索で-print0を使用し、grepで-Zを使用し、xargsで-0オプションを組み合わせて使用​​する改行ではなく、ファイル名間のnullバイト。

find ./recup*/ -name '*.txt' -print0 | xargs -0 grep -Zli "searchPattern" | xargs -0 cat
3
dannysauer

これは完全に最適なコードではありませんが、非常に単純であり、効率が問題でなければ問題なく機能します。問題は、文字列がすでに見つかった場合でも、ファイルを複数回グレップすることです。

まず、文字列を検索し、一致するファイルをリストに書き込みます。

find ./recup*/ -name '*.txt' -execdir grep -il "searchPattern" {} >> /tmp/file_list \;

この手順を繰り返して、必要に応じてsearchPatternを置き換えます。これにより、/tmp/file_listに一致するファイルのリストが生成されます。

問題は、このファイルに重複がある可能性があることです。したがって、重複を|sort|uniqに置き換えることができます。 sortパーツは重複を互いに隣接して配置するため、uniqは重複を削除できます。次に、catを使用して、これらのファイルをxargsでまとめることができます(各ファイル名は改行\nで区切ります)。したがって、

</tmp/file_list sort | uniq | xargs -d "\n" cat > final_file.txt

他の回答とは異なり、これには2つのステップと一時ファイルがあるため、検索するパターンが複数ある場合にのみお勧めします。

1
Sparhawk

シェルと環境に応じて、次のようにすることができます(bashの場合)

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1\|searchPattern2\|searchPattern3' "$file"; then
    cat "$file" >> some/other/file
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

パターンに従って結果を分離したい場合は、それを次のように変更できます

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1' "$file"; then
    cat "$file" >> some/other/file1
  Elif grep -qim1 'searchPattern2' "$file"; then
    cat "$file" >> some/other/file2
  Elif grep -qim1 'searchPattern3' "$file"; then
    cat "$file" >> some/other/file3
  fi
done < <(find ./recup*/ -name '*.txt' -print0)
0
steeldriver