改行コードの取り扱いについて勉強しなおした。

一つ前のエントリーを調べるに当たって勉強しなおしたのでまとめる。

\r, \n を各環境下で出力した場合、出力されるコード値それぞれ以下のようになる模様。

Linuxの場合

\r\x0d として出力され、
\n\x0a として出力される。

$ perl -e 'print "\r\n"' > sample.txt
$ od -tx1c sample.txt
0000000 0d 0a
         \r  \n
0000002

Windowsの場合

\r\x0d として出力され、
\n\x0d \x0a として出力される。

>perl -e "print qq(\r\n)" > sample.txt
>debug sample.txt
 -d
 351A:0100  0D 0D 0A 00 00 00 00 00-00 00 00 00 00 00 00 00   ...............

Perl内部では

\r\x0d として出力され、
\n\x0a として出力される。

Linuxで\r,\nを16進数出力

$ perl -e 'print unpack( "H*", "\r" ), "\n"';
0d
$ perl -e 'print unpack( "H*", "\n" ), "\n"';
0a

Windowsで\r,\nを16進数出力

>perl -e "print unpack( 'H*', qq(\r) )";
0d
>perl -e "print unpack( 'H*', qq(\n) )";
0a

Windowsにて、ファイル出力した場合のコード値とPerl内部のコード値が異なる

これに関しては、binmodeのドキュメントで詳しく説明がされていた。

Mac OS、全ての Unix 系、VMS の Stream_LF ファイルは テキストの外部表現として各行の末尾に 1 つの文字を 使っています(その文字は Mac OS では復帰で、 Unix とほとんどのVMS のファイルでは改行です)。 VMS, MS-DOS, MS-Windows 系といったその他のシステムでは、 プログラムからは \n は単純に \cJ に見えますが、 テキストファイルとして保存される場合は \cM\cJ の 2 文字になります。つまり、もしこれらのシステムで binmode() を使わないと、 ディスク上の \cM\cJ という並びは入力時に \n に変換され、 プログラムが出力した全ての \n は \cM\cJ に逆変換されます。 これはテキストファイルの場合は思い通りの結果でしょうが、 バイナリファイルの場合は悲惨です。

Perlの組み込み関数 binmode の翻訳 - perldoc.jp

なるほど。
改行コードの取り扱いが理解できた。
そして、binmodeが必要なタイミングというのもはっきりと分かった。