grep出力を短い行に制限する


8

私はしばしば次のような特定のエントリを持つファイルを見つけるためにgrepを使用します:

grep -R 'MyClassName'

良い点は、ファイルとその内容を返し、見つかった文字列を赤でマークすることです。悪い点は、テキスト全体が1つの大きな1行で記述されている巨大なファイルもあることです。これらの大きなファイル内でテキストを検索すると、grepが出力しすぎます。出力を例えば左と右に5ワードに制限する方法はありますか?または、出力を左と右に30文字に制限しますか?


3
結果をパイプでcut
送る

たとえば、探しているパターンが50の位置にあるが、30文字だけが必要だと言ったとしましょう。その行を無視するか、出力に含めますが、トリムしますか?正確に何を制限したいですか-検索または行自体?
Sergiy Kolodyazhnyy

1
@Rinzwind cut区切り文字または文字数でしか分割されないため、で何を実現したいのかよくわかりません。私がそれを含むラインを見つけたとき、MyClassNameそれはラインのどこにでもあり、常に同じ位置にあるとは限りません。さらに、その前後に文字のバリエーションがあり、区切り文字で分割される可能性がなくなります。
ソクラテス

1
@SergiyKolodyazhnyyで正の行MyClassNameが見つかった場合、結果として、ファイル名と、左右のx文字を取得したいと考えています。xは、私が提供する任意の数、たとえば30です。残りのファイルの内容は無視されます。これは、一致するファイルへのコンテキストを取得し、オーバーロードを制限するためです。
ソクラテス

1
@Rinzwindカスタム区切り文字のどのような種類のあなたが示唆しているcut以下の入力を持つ三つのファイルがある場合:oiadfaosuoianavMyClassNameionaernaldfajd/(/&%%§%/(§(/MyClassName&((/$/$/(§/$&public class MyClassName { public static void main(String[] args) { } }
ソクラテス

回答:


15

grepそれ自体には、行に基づくコンテキストのオプションのみがあります。代替案はこのSU投稿で提案されています

回避策は、オプション 'only-matching'を有効にしてから、RegExpの機能を使用して、テキストより少しだけgrepを実行することです。

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}" ./filepath

もちろん、色の強調表示を使用している場合は、いつでもgrepを実行して、実際の一致のみに色を付けることができます。

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}"  ./filepath | grep "WHAT_I_M_SEARCHING"

別の方法としてfold、テキストを入力してからそれをgreppingすることをお勧めします。例:

fold -sw 80 input.txt | grep ...

この-sオプションは、fold単語を途中で区切るのではなく、次の行にプッシュします。

または、他の方法を使用して、入力の構造に基づいて入力を行に分割します。(たとえば、SUの投稿はJSONを扱っていたためjq、pretty-printにgrep...を使用jqしたり、...だけでフィルタリングを実行したりすることは、上記の2つの方法のどちらよりも優れています。)


このGNU awkメソッドはより高速かもしれません:

gawk -v n=50 -v RS='MyClassName' '
  FNR > 1 { printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)}
  {p = substr($0, length - n); prt = RT}
' input.txt
  • 我々は(興味のあるパターンに分割されたレコードをawkを知らせる-v RS=...()、および文脈の文字数-v n=...
  • 最初のレコード(FNR > 1)の後の各レコードは、awkがパターンに一致するものを見つけたレコードです。
  • 印刷我々はそれほどn前の行(から文字を末尾p)とn現在の行(から先頭の文字substr($0, 0, n)(で前の行のためにマッチしたテキストと一緒に、) prt
    • 設定pprt 印刷した、設定した値は次の行で使用されます
    • RT これはGNUismです。そのため、これはGNU awk固有のものです。

再帰的な検索の場合、おそらく:

find . -type f -exec gawk -v n=50 -v RS='MyClassName' 'FNR>1{printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)} {p = substr($0, length-n); prt = RT}' {} +

2
わかりました。正規表現は有効なアプローチのようですので、ありがとうございます。ただし、処理時間はかなり長くなります。上記の投稿のようにRegexがない場合は4.912秒かかり、投稿のようにRegexがある場合は3分39.312秒かかります。
ソクラテス

1
@ソクラテスは、上で追加したawkメソッドのパフォーマンスが向上するかどうかを確認します
muru

1
このfoldメソッドは、検索された文字列が境界に表示されないことが確実な場合にのみ使用できますgrep。そうでない場合は、によって非表示になります。
Melebius

1
@muruでの提案に感謝しますgawk。残念ながら、find私のシステムで実行すると、ランダムなものを出力し、ファイル名を出力しないコマンドが推奨されます。さらに、awkコマンドを適切に分析するのに十分な流暢ではありません。現在、Regexと組み合わせてgrep問題を解決すると、高速ではない可能性がありますが、信頼性は高くなります。重ねて感謝します。
ソクラテス

1
@ソクラテスawkコマンドを修正できたと思います。私のメンタルモデルでは、どの行RTや接頭辞などを使用するかが間違っていました。
muru、

1

他のいくつかのオプション(以下を参照)と組み合わせて一致のみを使用すると、他の回答で述べた正規表現の処理オーバーヘッドなしで、探しているものに非常に近い可能性があります

grep -RnHo 'MyClassName'
  • n数値出力、一致の行番号を表示
  • Hファイル名、一致する行の先頭にファイル名を表示
  • o一致するだけで、行全体ではなく、計算された文字列のみを表示します

結果がはるかに速く見つかることは事実ですが、情報が不足しています。ファイルパスが表示され、行番号が表示されますが、テキスト出力は最初の検索のみMyClassNameです。したがって、コンテキストがありません。
ソクラテス

grep -RnHo "MyClassName"そしてgrep -Rno "MyClassName"同じ出力を持っています。
ソクラテス

@Socratesの出力は、同じディレクトリにHがないと同じではありません
Robert Riedl

-o正規表現は、いくつかの可変部分を持っていた場合はフラグが面白いかもしれません。固定文字列の場合、毎回印刷するのは無意味です。OPは近いコンテキストに関心がある可能性が高いです。
Melebius

1
@ソクラテス、本当-コンテキストがありませんが、それがポイントだと思いましたか?出力を制限しますか?前(-B 1)または後(-A 1)の行を追加して、コンテキストを再度追加できます。これ以上助けられなかったのでごめんなさい。
Robert Riedl
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.