id:eel3:20151212:1449931944 へのはてブのコメントより。
gawk なら簡単にできるけど、これも意外と知られてないかな。
http://b.hatena.ne.jp/entry/273514414/comment/Rocco
コメントのように、拡張アリアリなら、gawkで1文字/1byteずつ読むことや、mawkで1byteずつ読むことは可能である。例えば次のコードはgawkとmawk双方で有効だ。
$ echo $LANG ja_JP.UTF-8 $ echo -n aあbc | gawk ' > BEGIN { > FS = "" > RS = "^$" > } > { > for (i = 1; i <= NF; i++) > print $i > }' a あ b c $ _
FSに空文字列を設定することで、レコードをフィールド単位に分割せずに丸ごと読みこむようにしている。RSに正規表現^$
(決して何にもマッチしない)を設定することで、入力をレコード単位に分割せずに丸ごと読みこむようにしている。これで、改行コードだろうが何だろうが全て1文字/1byteずつ読むことが可能となる。
gawkはロケールのエンコーディングを解釈するので、この方法で1文字ずつ読むことができる。1byteずつ読みたい場合は、LANG=C
でgawkを実行するか、gawk 4.0以降ならオプション-b
ないし--characters-as-bytes
をつけて実行すればよい。
mawkは「マルチバイトってなに?」なawk実装なので、この方法で1byteずつ読むことになる。「1文字ずつ」は無理そうだ。
元ネタであるhcaslのsh版はPOSIX縛りだったのだが、POSIXにはFSに空文字列を設定した時の振る舞いについて、堂々と「unspecified」と書いてある。
If FS is a null string, the behavior is unspecified.
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html
もっともUnix環境のawkの場合、FSに空文字列を設定した時にgawkやmawkのように振る舞う実装は多いらしい。FreeBSDなどのmanを見た限り、少なくともnawkは同様に振る舞うようだ。
RSについては、そもそも正規表現を受けつける旨の記述が無い上に、2文字以上の文字列を設定した時の振る舞いが「unspecified」となっている。
If RS contains more than one character, the results are unspecified.
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html
FreeBSD、NetBSD、OpenBSDのawkのmanも、RSが正規表現を受けつける旨の記述はない。ということは、nawkも駄目っぽいのか?
ちなみにFSに2文字以上の文字列を設定した時は正規表現として扱われる。POSIXにもそう書かれている。しかしRSはそうではない。ちょっと混同しそうだ。