web-dev-qa-db-ja.com

開始パターンと終了パターンの間の行をgrepする方法は?

次の内容のファイルがあります。

zdk
aaa
b12
cdn
dke
kdn

入力1:aaaおよびcdn

出力1:

aaa
b12
cdn

入力2:zdkおよびdke

出力2:

zdk
aaa
b12
cdn
dke

以下のコマンドを使用して達成できます:

grep -a aaa -A2 file # Output 1
grep -a aaa -A4 file # Output 2

しかし、ファイルでは、終了文字列パターンの正確な発生(位置)が何であるかわかりません(ファイルには20000行があります)

どうすればこれを達成できますか?

31
Spike

grepはここでは役に立ちません。これは、範囲式を使用したsedでよりよく達成される仕事です。

$ sed -n '/aaa/,/cdn/p' file
aaa
b12
cdn
$ sed -n '/zdk/,/dke/p' file
zdk
aaa
b12
cdn
dke

sed -nは、自動印刷を抑制し、明示的に要求された場合にのみ行が印刷されるようにします。そして、これは/aaa/,/cdn/の範囲が発生したときに発生します。

これらの範囲式はawkでも使用できます。

awk '/zdk/,/dke/' file

もちろん、これらすべての条件をsed -n '/^aaa$/,/^cdn$/p' fileのようなより厳密な正規表現に拡張して、行がaaacdnだけで構成されていることを確認できます。

35
fedorqui

sedで実行できます

sed -n '
    /^aaa$/,/^cdn$/w output1
    /^zdk$/,/^dke$/w output2
    ' file
4
Costas

これがgrepコマンドです:

grep -o "aaa.*cdn" <(paste -sd_ file) | tr '_' '\n'

grepで複数行の一致を実現できますが、grep-P-OS Xなどのすべてのプラットフォームでサポートされているわけではありません)にはPerl正規表現を使用する必要があります。回避策として、改行を_文字に置き換え、grepの後に改行します。

または、 pcregrep を使用して、複数行のパターン(-M)をサポートすることもできます。

またはexを使用:

ex +"/aaa/,/cdn/p" -scq! file
1
kenorb