sed: 最後のパターン発生で終わる範囲があります(貪欲範囲)。

sed: 最後のパターン発生で終わる範囲があります(貪欲範囲)。

次のファイルをインポートします。

$ cat f1
stu vwx yza
uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno
jkl mno pqr
mno pqr stu
pqr stu vwx
stu vwx yza

最初の行から始めて、以下を含むabcすべての行を印刷します。最初mnoGNUが含まれますsed

$ sed -n '/abc/,/mno/p' f1
uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno

次回まですべての行を印刷するにはどうすればよいですか?最後のものContains mno、たとえば、次の結果をどのように取得できますか?

uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno
jkl mno pqr
mno pqr stu

つまり、GNUsedの範囲選択を貪欲にする方法はありますか?

修正する

私の設定では:

  • 欠落している場合は、mnoファイルの最後まですべての内容を印刷する必要があります。
  • mno最初の以前は発生できませんabc
  • 常に1つ以上があり、同じ行には決してありませんabcabcmno

編集するstu vwx yzaファイルを含む行で始まらないように、最初にダミー行を追加しました。 (abc最初の行から始まるソリューションを避けるために、ファイルは含まれているabc最初の行から始める必要があります。)

答え1

sed '/abc/,$!d;0,/mno/b;:1;/mno/b;$d;N;b1' file

動作アルゴリズム:
2つのアドレス範囲を使用します。
最初は、/abc/,$!d;最初のパターンマッチングの前にすべてを削除します。
2番目は、0,/mno/b;パターンが一致するまで各ラインバッファ(パターンスペース)を送信し、残りのスクリプトの/mno/出力をバイパスし、パターンがファイルに見つからない場合は削除を防ぎます。
残りのスクリプトは:1;/mno/b;$d;N;b1ループで動作します。エディタバッファでは、パターンマッチが発生するまで行が追加されます。パターンが見つかると、/mno/スクリプトの残りの部分をバイパスし、バッファ全体が出力に送信されます。一致するものがない場合は、バッファの最後の行を削除します。

答え2

awk可能であれば使用してください。パターンが始まる行とパターンが停止する行を表示し、ファイルの1パスでその行を印刷できます(abc最初の行から始めて最後の行までの行をバッファに保存することを含む)。

awk '/abc/ && !start {
  start = NR
}
/mno/ {
  stop = NR
}
start { line[NR] = $0 }
END {
  if ( !stop ) {
    stop = NR
  }
  for ( s = start; s <= stop; s++ )
    print line[s]
}' file

開始パターンがない場合、動作せず、一連の空白行のみが印刷されます。

答え3

awkバッファリングが少ない別の解決策:

awk '!f&&/abc/{f=1} f==1; f==2{buf=buf $0 ORS} f&&/mno/{f=2; printf "%s",buf; buf=""}' input.txt
  • これにより、最初の項目abc(フラグを1に設定)からf始まり、最初の項目まですべての内容が印刷されますmnof==1ルールブロックの外側のステートメントは、に設定されるたびに現在の行をawk印刷する必要があることを示します。f1
  • その後、各発生後mnof現在値2)、すべての行の内容がバッファに保存されbuf、次の発生時に印刷され消去されますmno。最初にmno発生した状況に正しく対応していることを確認してください。今後まず、このロジックを適用する前に少なくとも1に設定する必要がありますabcf

mnoしたがって、2つの出現の間、または最後の出現とmnoファイルの終わりの間に最大テキストを保存します(後者の部分は印刷されません)。

速度のためにメモリ効率を変えたい場合、次の2段階のアプローチはバッファリングにまったく依存しません。

awk 'FNR==NR{if (/abc/&&!start) {start=FNR} else if (/mno/) {end=FNR}; next} FNR>=start&&(!end||FNR<=end)' input.txt input.txt

その後、ファイルは2回処理されます(したがって、パラメータとして2回指定されます)。

  • 最初にFNR各ファイルのラインカウンタがグローバルラインカウンタと同じ場合、最初の発生と最後の発生を見つけて、対応する行NR番号をそれぞれに保存します。abcmnostartend
  • 2番目のパスでは、カウンタがendFNRの間に含まれるたびに(またはunset以上の場合)行を印刷します。startendstartend

答え4

abc予約済みスペース内の行から始めてすべての行を収集し、強欲属性を使用して.*最後の行以降のすべての行を削除できますmno

sed '/abc/,$!d;H;$!d;x;s/\n//;s/\(.*mno[^\n]*\).*/\1/'
  • /abc/,$!d最初の行の前にあるすべての項目(または行がまったくない場合はファイル全体)をd削除することです。abcabc
  • H;$!d予約済みスペースにファイル全体を収集するクラシックモード。 (非常に大きなファイルの場合は問題になる可能性があります。)
  • 大きなバッファコピーを避けるためにx使用する代わりにバッファを変更します。g
  • s/\n//空の予約スペースに追加して、生成された誤った開始改行を削除します。
  • s/\(.*mno[^\n]*\n\).*/\1/その後すべて削除最後 mno行(または行がない場合は、要求時に残りのファイル全体を印刷しますmno)。これは[^\n]POSIXではなく、GNUなどの特定のバージョンでのみ機能しますsed

関連情報