awk - 空のレコード区切り記号: "RS=" 対 "RS='|'" 対 "RS=(|)"

awk - 空のレコード区切り記号: "RS=" 対 "RS='|'" 対 "RS=(|)"

RS=レコード区切り文字をnull/空の文字列に設定できることはわかっていますが、GNUではawkRSを正規表現として定義することもできるので、これを使用することにしましたRS='|'RS=空の文字列(または|空の文字列しかし、これはリテラル|文字として扱われますが、これはRS='X|Y'正規表現(XまたはY)として正しく認識されます。

RS='|'awkが空の文字列として扱わないときに何が起こるのか誰かを説明できますか?

私も試してみましたがRS='(|)'全く違う話です。入力全体を単一のレコードとして扱うようです。

答え1

定義によるとRS='|' はい文字通りの意味|。すべての単一文字RSは、すべてのawk間の移植性のためにリテラルとして扱われます。それ以外の場合、スクリプトはRS='|'gawkとPOSIX awkで異なる動作をします。したがって、単一文字RSはリテラルであり、RSなどの複数文字文字列は正規表現です。 awkバージョンがそれをサポートしている場合、そうでなければ実際には文字列の最初の文字にすぎません(したがって常にRS='.'リテラルです。.場合によってはRS='.x'すべての文字の後に)xawsと他のテキストが続きます.

しかし、単一文字は他の正規表現コンテキストでPOSIXに対して定義されていない動作ですが、|などの正規表現反復文字の場合と同様に、多くのツールはそれをリテラルとして扱います|*?

- 「nullまたはnull」を意味する場合は、RS='(|)'「null」と同じように書くこともできます()。すべての文字が一致するようですが、なぜ一致しないのかわかりません。さまざまなツールは、さまざまな方法で正規表現を認識するようです。

$ printf 'foo\n' | sed -E 's/()/x/g'
xfxoxox
$ printf 'foo\n' | grep -Eo '()'
$
$ printf 'foo\n' | awk '{gsub(/()/,"x")} 1'
xfxoxox
$ printf 'foo\n' | awk -v RS='()' -v ORS='x\n' '1'
foox

私はGNU Awk開発者に連絡しました(参照:https://lists.gnu.org/archive/html/bug-gawk/2021-01/msg00003.html)そしてそれから2つを導きます:

  1. 空の文字列に一致する複数文字の正規表現は、レコード区切り文字またはフィールド区切り文字として使用しないでください。これにより、RS または FS がないものとして処理され、入力全体の単一レコード (RS の場合) またはレコード全体の単一フィールド (FS の場合) で終わります。これはgawkマニュアルの将来のバージョンで明示的に言及されます。
  2. gawk 5.1.0(おそらく以前のバージョンもあったかもしれません)には、上記の文が無視されたときに終了文字が消費されるバグがあります。これで修正が行われ、将来のgawkバージョンでリリースされる予定です。

関連情報