現在、解決に役立つ必要がある問題が発生しました。正しい方向を指すことでさえも役立ちます。
行の多いファイルがありますが、特定のパターンに従う特定の行「グループ」だけを抽出したいと思います。 (1行はで始まりA
、次の行はで始まりB
、次の行はで始まる必要がありますC
)
例:モード:、、A
順B
にC
始まります。
入力する:
A1
B1
C1
D1
A2
B2
D2
A3
D3
A4
B4
C4
A5
B5
D5
出力:
A1
B1
C1
A4
B4
C4
答え1
別の解決策awk
:
awk 'p2~/^A/ && p1~/^B/ && /^C/{print p2 RS p1 RS $0} {p2=p1; p1=$0}'
perl
入力全体を単一の文字列として読み込みます。
perl -0777 -ne 'print /^A.*\nB.*\nC.*\n/mg'
そしてリップグレップ便利なマルチラインマッチングオプションをサポートします。-U
rg -oUN '^A.*\nB.*\nC.*'
ここで-o
オプションは一致する部分だけを取得することであり、-N
オプションは出力で行番号を防ぐことです。
答え2
Sed ソリューションも必要な場合は見苦しいですが、うまくいきます。
sed -n '
/^A/{
N
/\nB/!D
N
/\nC/!{
s/\n//
D
}
p
}
' file
-n
p
sedに、コマンドに到達しない限り何も印刷しないように指示します。
最初の部分を理解すると、残りの部分も理解できます。
/^A/
パターン空間がAで始まると、N
パターン空間に次の行を追加します。/\nB/!D
パターン空間に B の後に改行文字がない場合、最初の改行文字の前の内容はすべて削除され、入力を読み取らずに結果パターン空間で再開されます。
短い冗談:sed -n '/^A/{N;/\nB/!D;N;/\nC/!{s/\n//;D};p}' file
答え3
次のawk
手順が機能します。
awk 's==2{if (/^C/) {s=0; p=p ORS $0; print p} else {s=0}}\
s==1{if (/^B/) {s=2; p=p ORS $0} else {s=0}}\
s==0{if (/^A/) {s=1; p=$0}}' input.txt
これは内部の「ステータス」フラグを維持してs
シーケンス内の任意の点(0:開始が見つからない、1:A
見つからない、2:シーケンスA
で見つかりましたB
)をチェックし、テキストをバッファに蓄積しますp
。
A
とが見つかり、B
現在の行がで始まる場合は、C
現在の行をバッファに追加して印刷します。状態リセット0
- 見つかり、
A
現在の行がで始まる場合は、B
現在の行をバッファに追加し、ステータスを2
(=A
とB
見つかります)に設定します。 - 先頭がまだ見つからず、現在の行がで始まる場合は、
A
それをバッファに追加してステータスをに設定します1
。
答え4
前の状態がA-> B-> Cにつながる場合にのみ、sedで状態マシンを設定して次の状態に進むことができます。
それ以外の場合は、髪を切って再起動してください。
$ sed -e '$d;/\n/d
/^A/N;/\nB/!D
$!N;/\nC/!D
' file
A1
B1
C1
A4
B4
C4
次のgrepコードは、PCREオプションでgnu grepをコンパイルした場合のもう1つの方法です。
$ grep -zoP '(?m)^A.*\nB.*\nC.*\n' file | tr -d '\0'