Sat Jun 10 16:22:33 JST 2006

ある perl のプログラムをダウンロードした。 ここでは仮に hello.cgi とする。

$ perl -wc hello.cgi
hello.cgi syntax OK
$ chmod 755 hello.cgi
$ ./hello.cgi
bash: ./hello.cgi: No such file or directory

となって動かない。ところが

$ perl hello.cgi
Content-type: text/plain

Hello

ちゃんと動く。ここで疑うのは先頭の一行。

$ head -n 1 hello.cgi
#!/usr/local/bin/perl

perl のパスはあっている。どこかほかのところが関係しているのかと思い vim で行を削除したりするとなんか変。 削除したはずの行が復活したりするのだ。そこで直感したのは文字以外の制御文字が入っているということ。

$ head -n 1 hello.cgi | od -bc
0000000   #   !   /   u   s   r   /   l   o   c   a   l   /   b   i   n
        043 041 057 165 163 162 057 154 157 143 141 154 057 142 151 156
0000020   /   p   e   r   l  \r  \n
        057 160 145 162 154 015 012
0000027

あそうか Windows で使われることを前提とされているために"復帰"(carriage return) が入っていたのか。 上の出力結果では \r 8進数の 015 です。

$ tr -d '\015' <hello.cgi >tmp.txt
$ cp tmp.txt hello.cgi

以上のようにして \r を取り除きました。


Thu Oct 18 14:27:58 JST 2007

代表的なOSの改行コード(newline) DOS, UNIX, Mac
システム改行コード記号8進数16進数
DOS (MS-DOS, Microsoft Windows)CR+LF\r+\n015+0120x0D+0x0A
UNIX (linux, FreeBSD, OS X, Solaris, AIX
などのUNIXおよびUNIX系OS)
LF (Line Feed: 改行)\n0120x0A
Mac (Mac OS Version 9まで)CR (Carrige Return: 復帰)
\r0150x0D

改行コードの変換

各種コマンドで変換

コマンド説明
newline - wikipedia
tr  tr -d '\r' < inputfile > outputfile  DOSをUNIXに変換 (CRを取り除く)
 MacをUNIXに変換 (CRをLFに置き換え)
sed  sed -e 's/\r$//' inputfile > outputfile
 
 DOSをUNIXに変換 (CRを取り除く)
  ) FreeBSDでは不可
 UNIXをDOSに変換 (LFの前にCRを追加)
  注) FreeBSDでは不可
awk  awk '{sub(/\r$/, ""); print}' inputfile > outputfile  DOSをUNIXに変換 (CRを取り除く)
 UNIXをDOSに変換 (LFの前にCRを追加)  
perl  perl -p -e 's/(\r\n|\n|\r)/\n/g'   inputfile > outputfile  UNIXに変換
 DOSに変換
 Mac(Version 9まで)に変換
nkf
 nkf -Lu -d inputfile > outputfile
 nkf -Lw -c inputfile > outputfile
 nkf -Lm    inputfile > outputfile
左のオプションに加えて以下のoutputfileの文字コードを指定する必要があります。
-j -s -e -w -w16
左から ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8N, UTF-16BE です。詳しくは‘man nkf‘で
 UNIX(LF)
 DOS(CR+LF)
 Mac(CR)
ruby  ruby -e 'while gets; gsub(/\r\n|\n|\r/,   "\n"); print; end' inputfile > outputfile  UNIX(LF)
 ruby -e 'while gets; gsub(/\r\n|\n|\r/, "\r\n"); print; end' inputfile > outputfile  DOS(CR+LF)
 ruby -e 'while gets; gsub(/\r\n|\n|\r/,   "\r"); print; end' inputfile > outputfile  Mac(CR)
python  python -c "import sys,re;[sys.stdout.write(re.sub('\r\n|\n|\r',  '\n',line)) for line in sys.stdin]" < inputfile > outputfile  UNIX(LF)
 python -c "import sys,re;[sys.stdout.write(re.sub('\r\n|\n|\r','\r\n',line)) for line in sys.stdin]" < inputfile > outputfile   DOS(CR+LF)
 python -c "import sys,re;[sys.stdout.write(re.sub('\r\n|\n|\r',  '\r',line)) for line in sys.stdin]" < inputfile > outputfile   Mac(CR)
PHP  php -r 'echo str_replace(array("\r\n","\n","\r"),  "\n", file_get_contents($argv[1]));' inputfile > outputfile  UNIX(LF)

FreeBSD の sed は \r を CRと解釈しないので、改行コードの変換は以下のようにします。ここで ^M は実際の制御文字で、Ctrlを押しながらvを押した後にCtrlを押しながらmを押します。

sed -e 's/^M$//' inputfile > outputfile       # DOSをUNIXに変換
sed -e 's/$/^M/' inputfile > outputfile       # UNIXをDOSに変換
   参考: FreeBSD QandA 375  —> FreeBSD の場合は port(/usr/ports/textproc/gsed) でGNU版sedが使えます。コマンド名は gsed(/usr/local/bin/gsed) です。

エディタで変換する。

エディタコマンド説明
※ 残念ながら改行コード(UNIX,DOS)が混在しているファイルには使えません。
vimvi互換エディタの一つで、多くのlinuxディストリビューションではviは
vimへのシンボリックリンクとなっている。
※ MS Windows上で編集された文書をUNIX系OS上で開いた場合文字化けして
編集できないことがあります。例として丸囲い数字(丸数字)、ローマ数字などを
含む文書です。
vim   :++e  fileformat=dos    改行コードをDOSとして読み直す  
  :set  fileformat=unix     UNIXに変換
  :set  fileformat=dos     DOSに変換
  :set  fileformat=mac     Macに変換
エディタコマンド説明
※ M-x はEscキーを押してすぐに x を押す。C-x はCtrlキーと同時にxを押す。
    RET はエンターキーを押す。
※ 改行コードと同時に文字コードも変換できる。 M-x set-buffer-file-coding-system RET utf-8-unix M-x set-buffer-file-coding-system RET shift_jis-dos M-x set-buffer-file-coding-system RET undecided-mac     undecided は文字コードは変換しないの意味。C-x  C-s で上書き保存。
    C-x  C-c でemacs終了。C-g はコマンドの取り消し。
emacs   M-x  set-buffer-file-coding-system  RET  unix   
  C-x  RET  f  unix
  UNIXに変換  
  M-x  set-buffer-file-coding-system  RET  dos   
  C-x  RET  f  dos
  DOSに変換
  M-x  set-buffer-file-coding-system  RET  mac   
  C-x  RET  f  mac
  Macに変換

ftp 転送モード ascii binary について

rfc959 は1985年10月に公開された File Transfer Protocol(FTP)の公式な仕様。インターネットにおける技術仕様や標準化の母体となる文書はInternet Engineering
Task Force(IETF)やInternet Society(ISOC)などで、広く意見を求めるという意味でRFC(A Request for Comments)という一連の文書として公開されている。
転送モードrfc959の記述
ascii 3.1.1.1. ASCII型
送信側は、データを内部文字表現形式から、標準的な8ビットNVT-ASCII
表現形式に変換する(Telnet仕様を参照)。受信側は、標準形式からその
内部形式に変換する。
WindowsからUNIX系サーバにテキストファイルをアップロードする場合、
改行コード\r\n\n に変換される。
UNIX系サーバからWindowsにテキストファイルをダウンロードする場合、
改行コード\n\r\n に変換される。
binary 3.1.1.3. イメージ型
データは転送のため8ビットにまとめられ、連続したビットとして,送信
される。受信側コンピュータはデータを連続したビットとしてそれを
蓄積しなければならない。
データは改変されない。
テキスト以外に使用。

UTF-8のファイルの先頭に謎のバイナリーデータが一体これは何か?

改行コードに加えて是非書き留めて置かなくていはいけないとがあります。それは文字コードがUTF-8の場合、そのファイルがBOM(Byte Order Mark)ありかBOM無しかということです。

> head -c 12 BOM.html | od -c -t x1
0000000  357 273 277   <   !   D   O   C   T   Y   P   E                
           ef  bb  bf  3c  21  44  4f  43  54  59  50  45                
0000014

ファイルの先頭に8進数で、357 273 277 16進数で ef bb bf のバイナリーデータが付加されていることが確認できます。このためにVim バージョン6.x では文字化けしてしまいます。またW3C Markup Validation Serviceでは以下のような警告が出ます。

  1. Byte-Order Mark found in UTF-8 File.

    The Unicode Byte-Order Mark (BOM) in UTF-8 encoded files is known to cause problems for some text editors and older browsers. You may want to consider avoiding its use until it is better supported.

文字コードがUTF-8のファイルに付加されたバイトオーダーマーク(BOM)はいくつかのテキストエディターや古いブラウザでは問題を起こすことが知られているとの事です。困ったことにBOMなしの場合逆に文字化けを起こしてしまうアプリもあるので要注意です。いくつかのエディターではファイルを保存する時、UTF-8(BOMあり)、UTF-8N(BOMなし)で選択できるようになっているようです。以下にperlで先頭のバイナリーデータを取り除くことができるかどうかのテスト例。(※ コマンドの先頭の``>''はpromptで、タイプするものではありません。)

> head -c 12 BOM.html | perl -pe 's/\357\273\277//' | od -c -t x1
0000000    <   !   D   O   C   T   Y   P   E                            
           3c  21  44  4f  43  54  59  50  45                            
0000011
> head -c 12 BOM.html | perl -pe 's/\xef\xbb\xbf//' | od -c -t x1
0000000    <   !   D   O   C   T   Y   P   E                            
           3c  21  44  4f  43  54  59  50  45                            
0000011

nkf(Network Kanji Filter)でもBOMを取り除くことができます。タイプミスの心配が少ないです。※ nkf バージョン2.06 は不可、2.08 可。

> nkf --version
Network Kanji Filter Version 2.0.8 (2007-07-20)
> head -c 12 BOM.html | nkf -w | od -c -t x1
0000000    <   !   D   O   C   T   Y   P   E                            
           3c  21  44  4f  43  54  59  50  45                            
0000011

in-placeで文字コードUTF-8のBOMありhtmlをBOMなしhtmlにするには以下のいずれかです。※ nkfのバージョン2.08以降。

> perl -p -i -e 's/\357\273\277//' BOM.html
> perl -p -i -e 's/\xef\xbb\xbf//' BOM.html
> sed -i -e 's/\xef\xbb\xbf//' BOM.html		# GNU版sed, freebsdの場合 textproc/gsed をインストールする必要あり。
> nkf --in-place -w BOM.html		# nkf version 2.08 以降
> nkf --overwrite -w BOM.html		# nkf version 2.08 以降

詳細は、`man perlrun`, `man nkf` で


newline