xtermでUTF-8が問題なく扱えることがわかったので、いよいよEUC-JPからUTF-8へのコンバートを決行します。

おおまかな手順は次のとおりです。

  1. 日本語ファイル名をUTF-8に変換する
  2. ロケールやエンコーディングなどの設定をUTF-8に変更する
  3. テキストファイルの中身をUTF-8に変換する

まず日本語ファイル名をEUC-JPからUTF-8に変換します。これは、convmvを使えば一発です(portはconverters/convmv)。基本的には

convmv -f euc-jp -t utf8 -r 対象ディレクトリ

で動作チェックし、問題なければ–notestを付けて再実行するだけです。私の場合は、いくつかのファイル名が「既にUTF-8だ」と誤認されたので、–nosmartで推測機能をオフにしました。また、変換したファイルの親ディレクトリのタイムスタンプが保存されるよう、–preserve-mtimesも付けました。

変換が終了したら、各種設定ファイルのロケールやエンコーディングをUTF-8に変更します。私の場合は、.xinitrcで「export LANG=ja_JP.UTF-8」に変えてXを再起動したのと、Sambaの設定ファイルsmb.confでunix charsetをコメントアウト(デフォルトはUTF8)してSambaを再起動した程度です。

テキストファイルの中身は、別にすべてをUTF-8にする必要もないので、ごく簡単な変換用のシェルスクリプトをつくっておいて、必要に応じて実行することにしました。スクリプトを作るときに念頭に置いたのは、次のような点です。

  • 複数ファイルをまとめて処理できる
  • ファイル名にスペースがあっても処理できる
  • 日本語を含まないテキストは触らない
  • 変換前ファイルをリネームして取っておく
  • タイムスタンプを保存する

実際のスクリプトはこんな感じ。

#!/bin/sh

# シェルスクリプトの引数で指定されたファイルを順番に処理する。
for file in "$@"; do
    # 元のファイル名にPIDを付加したものを一時ファイル名とする。
    temp="$file.$$"

    # とりあえずnkfでUTF-8に変換してみる。
    nkf -w "$file" > "$temp"

    # もし変換前後で差異がなければ、
    if cmp -s "$file" "$temp"; then
        # 変換しなかったことを表示する。
        echo "$file: intact"

        # 一時ファイルを削除して次のファイルへ。
        rm -f "$temp"
        continue
    fi

    # 処理対象ファイル名を表示する。
    echo "$file"

    # 一時ファイルのタイムスタンプを元ファイルと同じにする。
    touch -r "$file" "$temp"

    # 元のファイルのエンコーディングを調べて、ファイル名末尾に付加する。
    encoding=$(nkf --guess=1 "$file")
    mv "$file" "$file.$encoding"

    # 一時ファイルを元ファイルの名前にリネームする。
    mv "$temp" "$file"
done

実際にこれでいくつかのファイルを変換してみたら、思った以上にEUC-JPとShift_JISが混在していました。Sambaでファイル共有しているので、Windows側で作ったファイルはShift_JIS(たまにCP932)になっていたんですね。今後はUTF-8に統一するため、Windows側のテキストエディタのデフォルト設定もUTF-8に変更しました。

※バージョンメモ

  • FreeBSD 8.2-RELEASE
  • convmv-1.14
  • ja-nkf-2.1.1,1

■2011年5月6日追記

iTunesに いくつかのファイルが見つからないと言われて、全角の波ダッシュ”~”(EUCのA1C1)が半角のチルダ”~”(U+007E TILDE)に変換されてしまっていることに気づきました。当然ながらもともと半角チルダを使ってたファイルもあり、誤変換で生じたチルダと混ざってしまって、一括で直すこともでません。仕方なくconvmvしたときのログを見ながら、1つずつ手で直しました。

波ダッシュとチルダについては、有名な波ダッシュ問題というものがありますが(JIS X 0208の”~”(1区33点)をUnicodeのU+301C(WAVE DASH)に変換すべきところ、WindowsがU+FF5E(FULLWIDTH TILDE)に変換してしまう問題)、半角チルダに変換してしまうのはもっとひどいバグのような気がします。iconvは正しくWAVE DASHに変換してくれるので、perlのバグなのかもしれません。

ちなみに、Windows 7で波ダッシュを入力すると、Microsoft IMEでもGoogle日本語入力でも見事にFULLWIDTH TILDEになりました。FreeBSD側のMozcだとWAVE DASHになるので、気をつけないとまざっちゃうなあ……。

※バージョンメモ

  • libiconv-1.13.1_1
  • ja-ibus-mozc-0.13.523.102_1
  • Windows 7 Professional Service Pack 1
  • Microsoft IME 10.1.7601.0
  • Google日本語入力 1.0.556.0