grepはファイルのn行をスキップし、後に検索します


9

巨大なログファイルがあり、パターンの最初の発生をgrepし、この発生の直後に別のパターンを見つけたいと考えています。

例えば:

123
XXY
214
ABC
182
558
ABC
856
ABC

私の例では182次の出現を見つけて見つけたいと思いますABC

最初の発生は単純です:

grep -n -m1 "182" /var/log/file

これは出力します:

5:182

ABCの次の出現を見つけるにはどうすればよいですか?

私の考えは、182の行番号に基づいて、grep最初のn行を(上記の例ではn=5)スキップするように指示することでした。しかし、どうすればよいですか?


1
grep使用される要件ですか?私はこれでできるとは思いませんgrepが、awkor sed(単独で、またはと組み合わせてgrep)で簡単にできます。
Hauke Laging、2015年

@HaukeLaging grepは不要です。sedまたはにまだ慣れていませんawk。良い解決策があれば、聞かせてください!:) @don_crissti最初の行だけが印刷されます。他の出来事は気にしません。
koljanep、2015年

回答:


10

ではsed、あなたは範囲と使用することができq、単一の終了時にUIT入力:

sed '/^182$/p;//,/^ABC$/!d;/^ABC$/!d;q'

同様に、GNU grepでは、入力を2つgrepのsに分割できます。

{ grep -nxF -m1 182; grep -nxF -m1 ABC; } <<\IN
123
XXY
214
ABC
182
558
ABC
856
ABC
IN

...印刷する...

5:182
2:ABC

...最初にixed-stringリテラルがgrep見つかり、行全体182がその読み取りの開始から5行と一致し、2番目が同様に型指定されたABC一致がその読み取りの開始から2行または2行と一致したことを示します5行目で最初の読み終わり-F-xgrep

からman grep

-m NUM, --max-count=NUM
          Stop  reading  a  file  after  NUM  matching
          lines.   If the input is standard input from
          a regular file, and NUM matching  lines  are
          output, grep ensures that the standard input
          is  positioned  to  just  after   the   last
          matching  line before exiting, regardless of
          the  presence  of  trailing  context  lines.
          This  enables  a calling process to resume a
          search. 

再現可能なデモンストレーションのためにヒアドキュメントを使用しましたが、おそらく次のようにする必要があります。

{ grep ...; grep ...; } </path/to/log.file

また、次のような他のシェル複合コマンド構文でも機能します。

for p in 182 ABC; do grep -nxFm1 "$p"; done </path/to/log.file

+1マンページでそれを見た。それは私が試したものです、grepの代わりにの間にパイプを;
置い

@ Xen2050-通常、パイプは機能しません-入力を共有する場合、通常、lseekableファイルが必要です。
mikeserv 2015年

印象的な答えですが、パイプラインについてのあなたの声明はサポートしていません。2つgrepのsが共有するhereドキュメントは、事実上、それらのパイプラインです。その他:マーカー線を印刷せずに試しましたsed '//,/^ABC$/!d;/^ABC$/!d;q'が、奇妙なエラーが発生しました。何をし//ますか?
Hauke Laging、2015年

1
@HaukeLaging-here-document (ほとんどのシェルの場合)はパイプではありません-これはシェルが作成した実際のtmpファイルであり、記述子を維持しながら書き込みを行う前にシェルが削除します。それはまだ調査可能です。パイプは一般に、検索可能ではありません。私はそのsedことを見ていきます-本当に速く書いただけです。
mikeserv 2015年

1
@HaukeLaging-ああ、それでうまくいきsedます-あなたは参照を省略しました。ではsed、あなたは、最後に参照することができ/address/、空に再び//アドレス。だから、/^182$/command;//,/next_address/ちょうどありません/^182$/command;/^182$/,/next_address/。GNUを使用している場合エラーはおそらく以前の正規表現ではありませんでしたsed。ちなみに、パイプのlseek /dev/fd/[num]は、Linuxシステムのリンクを介して間接的に操作できます。ただし、バッファを(のようにddうまく処理しない、通常は負けてしまいます。
mikeserv 2015年

2

使用grep(Perl互換の正規表現でpcregrep):

pcregrep -Mo '182(.|\n)*?\KABC'

オプションは-M、パターンが複数の行に一致することを許可し\K、一致したパターン(この時点まで)を出力に含めません。\K結果としてリージョン全体が必要な場合は削除できます。


2
> awk '/^182$/ { startline=1; }; startline == 0 { next; }; /^ABC$/ { print "line " NR ": " $0; exit; }' file
line 7: ABC

1
これは最初のABCをどこにでも与えます。この質問は、最初のABCたい最初の182ほとんどの直接のようなフラグがあるawk '/^182$/{z=1;next} z&&/^ABC$/{print NR":"$0;exit}' file-またはあなたが少なくとも一つの明示的な書き込みをすることができgetline()、通常はclumsierでループを、あるいは巧妙なことがほとんどJRFergusonのperlの@のような範囲を使用して(?):awk '!x&&/^182$/,/^ABC$/ {x=NR":"$0} END{print x}
dave_thompson_085

@ dave_thompson_085確かに。正しいアイデアですが、ひどくコード化されています(執筆中に2つのアイデアを混ぜ合わせました)。恥ずかしいことに私も試しましたが、出力に疑問はありませんでした。
Hauke Laging、2015年

1

使用できるPerlのバリエーションは次のとおりです。

perl -nle 'm/182/../ABC/ and print' file

...一致する範囲の行を印刷します。

ファイルに複数の一致する範囲が含まれている場合、/区切り文字を次のように変更して、出力を最初の範囲のみに制限できます。?

perl -nle 'm?182?..?ABC? and print'

1

に固執しgreptail&を追加するとcut、次のことができます...

の最初の一致の行番号のgrep 182

grep -m 1 -n 182 /var/log/file |cut -f1 -d:

全てをgrepすることを利用ABC「を使用して、唯一の上記第一の整合ライン後のsはtails」の-n +Kk番目の行の後に出力します。すべて一緒に:

tail -n +$(grep -m 1 -n 182 /var/log/file |cut -f1 -d:) /var/log/file | grep ABC

または-m 1もう一度追加して、最初に一致したものだけを検索しますABC

tail -n +$(grep -m 1 -n 182 /var/log/file|cut -f1 -d:) /var/log/file|grep -m 1 ABC

参照:
manページ
/programming/6958841/use-grep-to-report-back-only-line-numbers


1

別の変形はこれです:

grep -n -A99999 "182" /var/log/file|grep -n -m1 "ABC"

フラグ-試合後99行目と99999文字は、見逃さないようにするためのものです。大きいファイルにはもっと行が必要です( "wc -l"で確認してください)。


0

範囲演算子,をここで使用することができます:

< yourfile \
sed -e '
   /182/,/ABC/!d
   //!d;=;/ABC/q
' | sed -e 'N;s/\n/:/'

..match-only-once演算子と連携した範囲演算子は、m??ここで使用できます。Perl

perl -lne 'm?182? .. m?ABC? and print "$.:$_" if /182/ || /ABC/' yourfile
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.