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


11

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

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

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

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

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

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

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


したがって、指定したコマンドを使用すると、探している結果が得られますが、出力をテキストファイルにリダイレクトしようとしていますか?
ryekayo 2014

私の質問を読んだ後、「Go through ...」で始まる段落は、擬似コードのように聞こえます。たぶん、数行のfor / if Pythonコードでコードを取得できます。私はより多くの情報に基づいた応答を待っている間それを打つでしょう
アミ

それは確かに疑似コードであり、bashでもそれを行う方法を見つけることができると思います。
ryekayo 2014

@ryekayo、はい、それは私に出力を与えますが、それは特定のタイプのデータがどのファイルにあるかを見つけるだけであり、そのデータのより多くがそのファイルにあることを教えてくれます。そのため、そのファイルのすべてを取得して、別のファイルに書き込みたいと思います。
亜美

おそらく、そのコマンドを何らかのifステートメント、またはifステートメントのケースまたは結果に基づいて内容を
抽出

回答:


10

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

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


はい、それでうまくいくと思います。そして、それは私に仕事の基盤を与えてくれます。複数の文字列を検索するので、複数のelifを使用したfor / ifビットのコードは、タスクを自動化するのに役立ちます。ありがとう
Ami

それは私が考えていたものよりももっと良いです笑
ryekayo

それはうまくいかなかったようです。このエラーが発生しました:「/ usr / bin / findを実行できません:引数リストが長すぎます」
Ami

@Amiは回答を更新し、その問題の解決策を提供しました。
Patrick

2
あなたが複数の文字列を使用している場合@Ami、(ちょうど別のファイルにすべての正のファイル名を保存する方が簡単かもしれませんgrep -lそして、)|sort|uniqcatファイルリストから。
スパーホーク2014

3

パターンを出力するのではなく、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

2
私はまた、Patrickの「2つの-exec」オプションも気に入っています。ただし、すべてのファイルに対して新しいfork(まあ、clone())とexecが実行されます。通常\+は、\;その問題を回避するためではなく使用できますが、-exec引数のペアでそれがどのように機能するかはわかりません(私は「悪い」と思います)。xargsのペアを使用すると、いくつかの新しいプロセスが生成されるだけで、多くのファイルで高速になります。
dannysauer 2014

これもよさそうです。ありがとう。noobの1つの質問:最後のxargsの後の猫はファイルに出力する必要がありますよね?
アミ

私が最初に読んだとき、ファイルの内容がどこに行くべきかという質問は指定されていないと思いました。あなただけのアペンド(最後まで)と思いますので、これらのコマンドのすべての3つは、ファイル(複数可)STDOUTに内容を置く>afileか、|acommandまたはあなたの状況に適したものは何でも。:)
dannysauer

良い答えです、pg_hba.confを猫にする必要がありましたsudo find /* -name pg_hba.conf | xargs sudo cat
App Work

これは少し話題から外れていますが、sudo xargsではなくを使用することを好みxargs sudoます。を実行xargs sudoすると、コマンドがであると想定してコマンドラインが作成されsudo cat argsます。ただし、猫は/ binにあるため、sudoが実行され/bin/cat argsます。コマンドが/ usr / local / binなどの長いディレクトリにある場合、sudoコマンドを実際に実行すると、コマンドラインが長すぎたり、追跡が困難なエラーが発生したりする可能性があります。その上、sudo xargsxargsを実行したことだけをログに記録しxargs sudo、すべての引数を使用してコマンドをログに記録します。その結果、sudoログ行が長くなります。:)
dannysauer 2017年

1

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

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

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

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

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

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

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


0

シェルと環境に応じて、次のようにすることができます(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)

「完了」後のビットは何をしますか?実際に好きなのは、一致したパターンを含むファイルが別のファイルに書き込まれるように、ifブロックを変更することです。
亜美

見つかった「.txt」ファイルのみがリストされ、それぞれがヌル文字で終了しています(スペースやその他の文字を含むファイル名に対して安全であるため)。次に、whileループはそのリストを読み取り、grep/条件cat部分を実行します。
スチールドライバー、2014

私は、コードを実行しようとすると、私はこのエラーを取得する:./recoverData.sh:構文エラー:「(」予期しないfindコマンドの周りのブラケットから来ている。
亜美

どのシェルを使用していますか?プロセス置換構文はbashに固有です-したがって、私の資格は「シェルと環境によって異なります」
steeldriver

1
コマンドを対話型のbashシェルで直接実行するか、最初の行にshebangが含まれるファイルに入れて、#!/bin/bashで実行可能にしchmod +x recoverData.sh、を使用して実行でき./recoverData.shます。んではない使用sh recoverData.shするので/bin/sh可能性があるdashシェル
鋼のドライバー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.