POSIX.2の最後のトークンからEOFにテキストをインポートする

POSIX.2の最後のトークンからEOFにテキストをインポートする

次のように表示された行があるテキストがあります。

aaa
---
bbb
---
ccc

最後のトークン(排他)のテキストをEOFにインポートする必要があります。この場合、

ccc

POSIX.2にエレガントな方法はありますか?今度は2回の実行を使用します。最初の実行nlgrepその行番号を持つ最後の実行。その後、行番号を抽出してsed問題ブロックを抽出するために使用しました。

テキストセグメントは非常に大きくなる可能性があるため、テキストをバッファに追加するなど、いくつかのテキストを追加する方法を使用することが心配です。マーカーが見つかると、バッファを空にしてEOFの最後のチャンクバッファを取得します。

ベストアンサー1

セグメントが非常に大きくない限り(たとえば、大容量ファイルシステムを制御する小さな組み込みシステムであるため、実際にそのような多くのRAMを節約できない場合)、単一パスは実際にはより良いアプローチです。速度が速くなるだけでなく、最も重要なのは、ソースをストリームにすることができ、読み取り後に保存していないすべてのデータが失われることです。 sedもできますが、これは実際にawkの仕事です。

sed -n -e 's/^---$//' -e 't a' \
       -e 'H' -e '$g' -e '$s/^\n//' -e '$p' -e 'b' \
       -e ':a' -e 'h'              # you are not expected to understand this
awk '{if (/^---$/) {chunk=""}      # separator ==> start new chunk
      else {chunk=chunk $0 RS}}    # append line to chunk
     END {printf "%s", chunk}'     # print last chunk (without adding a newline)

2段階の方法を使用する必要がある場合は、最後の区切り文字の行オフセットを決定して印刷します。またはバイトオフセットを決定し、それから印刷します。

</input/file tail -n +$((1 + $(</input/file         # print the last N lines, where N=…
                               grep -n -e '---' |   # list separator line numbers
                               tail -n 1 |          # take the last one
                               cut -d ':' -f 1) ))  # retain only line number
</input/file tail -n +$(</input/file awk '/^---$/ {n=NR+1} END {print n}')
</input/file tail -c +$(</input/file LC_CTYPE=C awk '
    {pos+=length($0 RS)}        # pos contains the current byte offset in the file
    /^---$/ {last=pos}          # last contains the byte offset after the last separator
    END {print last+1}          # print characters from last (+1 because tail counts from 1)
')

付録:POSIX以上のものがある場合、レコード区切り文字がRS正規表現になることを可能にするawkの一般的な拡張に依存する単純な使い捨てバージョンがあります(POSIXは単一文字のみを許可します)。完全に正確ではありません。ファイルがレコード区切り文字で終わる場合は、空のレコードの代わりに最後のレコード区切り文字の前のブロックを印刷します。使用される2番目のバージョンはRT欠陥を防ぎますが、RTGNU awkに固有のものです。

awk -vRS='(^|\n)---+($|\n)' 'END{printf $0}'
gawk -vRS='(^|\n)---+($|\n)' 'END{if (RT == "") printf $0}'

おすすめ記事