web-dev-qa-db-ja.com

2つのパターンの間にあるsed検索の2番目またはn番目の一致を出力します

以下に示すように、2つのパターンに基づくsed検索のn番目の一致を出力したいと思います。

sed -n '/start here/,/end here/p'  'testfile.txt' 

testfile.txtに以下のテキストが含まれているとします。

start here
0000000
0000000
end here
start here
123
1234
12345

123456
end here
start here
00000000
end here
00000000

00000000

そして、私は2つのパターンの間にゼロを印刷したくありません。

上記のコマンドに基づいて、パターン間のすべての一致を取得します。その出力を以下に示します。

start here
0000000
0000000
end here
start here
123
1234
12345

123456
end here
start here
00000000
end here

私の望ましい出力は:

start here
123
1234
12345

123456
end here

行がtestfile.txtのように印刷され、連結されていない必要があることを考慮してください。

5
dropdown

別のツールに切り替えるだけです。 Perl、例えば:

_Perl -ne '$k++ if /Pattern1/; if(/Pattern1/ .. /Pattern2/){print if $k==3}' file
_

これで3番目の一致が出力されます。 _$k==3_を任意の値に変更します。ロジックは次のとおりです。

  • _$k++ if /Pattern1/_:この行が_$k_と一致する場合は、変数_Pattern1_の値を1つ増やします。
  • if(/Pattern1/ .. /Pattern2/){print if $k==3}:この行が_/Pattern1/_から_/Pattern2/_の範囲内にある場合、印刷しますが、_$k_が3の場合に限ります。この値を必要に応じて変更します。

これを小さなシェル関数にラップして、N番目の一致をより簡単に取得できます。

_getNth(){
  pat1="$1"
  pat2="$2"
  n="$3"
  file="$4"

  Perl -ne '$k++ if /'"$pat1"'/;if(/'"$pat1"'/ .. /'"$pat2"'/){print if $k=='"$n"'}' file

}
_

その後、次のように実行できます。

_getNth Pattern1 Pattern2 3 'huge file.txt' 
_

サンプルデータを使用する:

_$ Perl -lne '$k++ if /start here/;if(/start here/ .. /end here/){print if $k==2}' testfile.txt
start here
123
1234
12345

123456
end here
_

または:

_$ getNth 'start here' 'end here' 2 testfile.txt
start here
123
1234
12345

123456
end here
_

ちょうど楽しみのために、ここに別のPerlアプローチがあります:

_$ Perl -lne '($k++,$l++) if /start here/; print if $l && $k==2; $l=0 if /end here/' testfile.txt 
start here
123
1234
12345

123456
end here
_

または、ゴルフが好きなら(@simlevに感謝):

_Perl -ne 'print if /^start here$/&&++$k==2../^end here$/' testfile.txt 
_
5
terdon

@ terdon が賢明に示唆しているように、私はこれをPerlで解決します。またはAWKを使用:

awk '/start here/&&++k==2,/end here/' testfile.txt

(OPがコメントで述べているように)sedを単独で使用しなければならない場合は、より複雑で、読みにくく、カスタマイズしにくいものを思い付きます。

sed -n '/start here/{:A n; /end here/b B; b A}; :B n; /start here/{p; :C n; p; /end here/q; b C}; b B' testfile.txt
1
simlev