GNU -zオプションなしでsedを使用して1つのバッファでファイル全体を処理する方法は?

GNU -zオプションなしでsedを使用して1つのバッファでファイル全体を処理する方法は?

不明な行数のパターンマッチングや「...の最後の項目を置き換える」などのいくつかの問題では、-zGNUオプションがsed本当に役に立つ可能性があります。同じ移植性をどのように取得できますか?

例: ファイルがあります。

yellow, green,
blue, black, purple,
orange,
white, red, brown
are some colours

ファイルの最後のコンマをに置き換えたいですand。カンマがどの行にあるのか、行のどこにあるのかわかりません。 GNUで私はsedできる

sed -z 's/\(.*\),/ \1 and/'

希望の出力を得る

yellow, green,
blue, black, purple,
orange,
white, red and brown
are some colours

POSIXで実行できる移植可能な方法でこれをどのように実行できますかsed

答え1

純粋なPOSIXでは、sedすべての行を直接貼り付ける必要があります。一部の人はNループ内でこれを行いますが、最も簡単な方法は次のパターンを使用して予約済みスペースに追加することですH;1h;$!d;x

  • H各行を予約済みスペースに追加します。残念ながら、最初の行を追加すると、バッファの先頭に改行文字が追加されます。
  • 1h改行を防ぐために、最初の行の予約済みスペースを上書きします。
  • $!d最後の行を除くすべての行の処理は終了します。予約済みスペースに保存されるため、印刷する必要はありません。
  • x最後の行以降にのみ実行され(他のすべての行では追加のdコマンド処理が停止します)、予約済みスペースとパターンスペースは変更されますx。したがって、このコマンドの後は、予約済みスペースに収集されたファイル全体がパターンスペースに存在します。-zGNUを選択してくださいsed。もちろん、g代わりに使用することもできますが、xこれによりコピー量が増えるため、x速度が速くなります。

したがって、この例のスクリプトは次のようになります。

sed 'H;1h;$!d;x;s/\(.*\),/\1 and/'

参考にしてください非常に大きなファイルの場合はRAMを大量に使用するため、これらのファイルを処理することはお勧めできません。

答え2

sedは、単一の文字列に対して単純なs / old / new操作を実行するために使用されます。 s、g、p(-nを含む)以外の構文を使用するほとんどすべての場合と確かに「空間予約」について話す場合は、間違ったツールを使用していることです。このようなs / old / newよりも複雑な操作の場合は、代わりにawkを使用する必要があります。以下は、UNIXシステム上のすべてのシェルでawkで動作し、ファイル全体をメモリに保存せず、テキストで他の操作を実行したい場合は調整が簡単です。

$ cat tst.awk
/,/ { printf "%s", prev; prev="" }
{ prev = prev $0 ORS }
END {
    if ( match(prev,/.*,/) ) {
        prev = substr(prev,1,RLENGTH-1) " and" substr(prev,RLENGTH+1)
    }
    printf "%s", prev
}

$ awk -f tst.awk file
yellow, green,
blue, black, purple,
orange,
white, red and brown
are some colours

ファイル全体をメモリに入れて、次の不思議なルーンを書くことで、awkで簡単にこれを行うことができます。

$ awk '{r=r$0 ORS} END{h=r;sub(/,[^,]+$/,"",h);sub(/.*,/,"",r);printf "%s and%s",h,r}' file
yellow, green,
blue, black, purple,
orange,
white, red and brown
are some colours

しかし、ポイントはsedとは異なり、それを必要としないということです。

関連情報