web-dev-qa-db-ja.com

行のgrepコンテキストをN文字に制限する

行の長さが数千文字を超えるJSONファイルをgrepする必要があります。 一致の左側と右側に最大N文字のコンテキストを表示するようにgrepを制限するにはどうすればよいですか?一般的なLinuxパッケージで使用できる限り、grep以外のツールでも問題ありません。

これは想像上のgrepスイッチФの出力例です:

$ grep -r foo *
hello.txt: Once upon a time a big foo came out of the woods.

$ grep -Ф 10 -r foo *
hello.txt: ime a big foo came of t
36
dotancohen

GNU grep

N=10; grep -roP ".{0,$N}foo.{0,$N}" .

説明:

  • -o =>一致したもののみを印刷
  • -P => Perlスタイルの正規表現を使用
  • 正規表現は、0〜$N文字の後にfooが続き、その後に0〜$N文字が続くと言います。

GNU grepがない場合:

find . -type f -exec \
    Perl -nle '
        BEGIN{$N=10}
        print if s/^.*?(.{0,$N}foo.{0,$N}).*?$/$ARGV:$1/
    ' {} \;

説明:

grepがGNU grepであることに依存できなくなったため、findを利用してファイルを再帰的に検索します(-r action of GNU grep)。見つかったファイルごとに、Perlスニペットを実行します。

Perlスイッチ:

  • -nファイルを1行ずつ読み取ります
  • -l各行の末尾の改行を削除して、印刷時に元に戻します
  • -e次の文字列をコードとして扱います

Perlスニペットは基本的にgrepと同じことをしています。まず、変数$Nを必要なコンテキスト文字の数に設定します。 BEGIN{}は、これがすべてのファイルのすべての行に対して1回ではなく、実行の開始時に1回だけ実行されることを意味します。

各行に対して実行されるステートメントは、正規表現の置換が機能する場合に行を出力することです。

正規表現:

  • 古いものを怠惰に一致させる1 行の先頭(^.*?)の後にgrepの場合と同様に.{0,$N}が続き、その後にfoo後に別の.{0,$N}が続き、最後に古い行の終わりまで遅延すること(.*?$)。
  • これを$ARGV:$1に置き換えます。 $ARGVは、読み込まれている現在のファイルの名前を保持する魔法の変数です。 $1は、括弧が一致したものです。この場合のコンテキストです。
  • 貪欲な一致はfooの前にすべての文字を消費するため、一致に失敗することはないため(.{0,$N}は0回一致できるため)、両端での遅延一致が必要です。

1つまり、全体的な一致が失敗しない限り、何も一致させないことをお勧めします。つまり、できるだけ少ない文字数で一致させます。

25
Joseph R.

これを使ってみてください:

grep -r -E -o ".{0,10}wantedText.{0,10}" *

-Eは、拡張正規表現を使用することを示します

-oは、一致のみを印刷することを示します

-r grepはフォルダ内で再帰的に結果を探しています

正規表現:

{0,10}は、印刷する任意の文字数を示します

は任意の文字を表します(ここでは文字自体は重要ではなく、番号のみが重要でした)

編集:ああ、なるほど、ジョセフは私と同じソリューションを推奨している:D

22
Eenoku

-bフラグを使用してstdoutをcutにパイプします。grepの出力に1行あたり1〜400バイトだけを指示できます。

grep "foobar" * | cut -b 1-400
4
Eric Leschinski

以下から取得: http://www.topbug.ne​​t/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/ および https://stackoverflow.com/a/39029954/1150462

推奨されるアプローチ".{0,10}<original pattern>.{0,10}"は、ハイライトの色がしばしばめちゃくちゃになることを除いて、完全に良いです。同様の出力でスクリプトを作成しましたが、色も保持されています。

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 | grep --color=none -oE ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

スクリプトがgreplとして保存されているとすると、grepl pattern file_with_long_linesは、一致する行を表示しますが、一致する文字列の前後に10文字しかありません。

2
xuhdev