スクリプトで grep の出力を安全に使用するにはどうすればよいでしょうか?

スクリプトで grep の出力を安全に使用するにはどうすればよいでしょうか?

スクリプトで、テキストを含むファイルを検索したいのですが、テキストが見つかったファイルと、テキストが見つかったファイル内の全行を知る必要があります。 はgrepこれを行うユーティリティですが、ファイル名にテキストが含まれている場合、出力を使用可能な形式にするにはどうすればよいでしょうか。コマンドによくあるような、使用できる:何らかの--porcelainモードはありますか。grepgit

test-num:1:date:jan-2例: grep で調べたい名前のファイルがいっぱい入ったフォルダーがあります。ファイルには、FAILURE:<some reason>またはSUCCESS:<some reason>(他にもいろいろ) が含まれています。特定の理由を検索し、ファイル名と理由 (テキストの行全体でもかまいません) を後で処理するために保存するスクリプトが必要です。出力は、コードを実行できる限り、どのようなデータ構造でもかまいません。

答え1

というものは存在しません。grep --porcelainファイル名の特殊文字の処理は、UNIX では常に後付けでした。効率を犠牲にして、次のような方法を試すことができます。

pattern='some pattern'
for file in ./*; do
    grep -- "$pattern" "$file" | while read -r line; do
        printf 'file: %s, line: %s\n' "$file" "$line"
    done
done

答え2

-ZGNU grep の最近のバージョンには、出力を明瞭にするオプションがありますが、これは主に のような用途を対象grep -lZ … | xargs -0としています。行の内容をリストする場合、コロンがヌルバイトに置き換えられ、行の内容は依然として改行で終わる¹ ため、これはまだ機能しますが、シェルはヌルバイトの処理が得意ではないため、この出力を解析するのは困難です。

1 つの簡単な解決策 (パフォーマンスは若干低下しますが) は、各ファイルに対して grep を個別に実行することです。

別の解決策としては、Perl や Python などの言語を使用することです。Perl は grep をエミュレートするのに非常に優れています。 grep REGEX基本的には ですperl -ne '/REGEXP/ and print'

しかし、出力が実際には曖昧でない場合は、これはまったく必要ないかもしれません。たとえば、一致する行にコロンが含まれていない場合、ファイル名は最後のコロンまでの行のすべてになります。一致する行がすべてSUCCESSorで始まりFAILURE、これらの単語がファイル名に表示されない場合は、これを使用して区切りなどを特定できます。

¹改行で終了するレコードではなく、ヌルで終了するレコードをフィルター処理する場合を除き、ヌルはファイル名のターミネータと結果のターミネータの両方になります。出力がなくても、ファイル名と出力内の一致するレコードが交互に出力レコードとして表示されるため、出力は依然として明確です。-z-o

答え3

grepの出力を安全に使用する方法スクリプトでは?

...出力はどんな形式でも構いませんデータ構造、コードを実行できる限りは。

シェルスクリプトには実際にはデータ構造がありません。配列はありますが、それだけです。また、パイプ出力を安全に配列に取り込むのは簡単ではありません。(ファイル名できる改行を含みます。

最善の方法はコードを実行するシェル スクリプトでファイルを実行する場合は、ファイルに対してコードを実行するだけで、後で使用するためにファイル名を保存しないでください。

これを行うには、次を使用しますfind

find somedir -type f -exec grep -q somepattern {} \; -exec somecommand {} \;

しかし、あなたの質問をよく読むと、あなたは実際にはコードを実行するファイル全体にわたって、特定の行に対してテキスト処理を実行したいだけです。この場合、おそらく GNU Grep オプションが-z適しています。これと、Sed または Awk の知識があれば、質問に対処できます。


ファイルの命名規則を変更するのが賢明かもしれません。

関連情報