受け取った CSV を開いたら、日本語の列がまるごと記号の羅列になっていた。
ファイルが壊れたわけではなく、多くの場合は「保存したときの文字コード」と「開いたときの文字コード」がずれているだけです。
この食い違いをコマンド1行で埋められるのが iconv というツール。
この記事では、iconv の基本と、変換できない文字にぶつかったときの逃げ道までを、手元で実際に動かした結果と一緒に整理します。
iconv とは何をするコマンドか
iconv は、テキストの文字コードを別の文字コードへ変換して標準出力へ流すコマンドです。
変換元を -f(from)、変換先を -t(to)で指定する、という組み立て。
文字そのものを書き換えるのではなく、同じ文字を別の符号で書き直しているだけ、と捉えると挙動が読みやすくなります。
そもそも文字コードとは何で、なぜ化けるのかは、こちらの記事で整理しました。
基本の使い方
変換して別ファイルに書き出す
いちばん出番が多いのは、Windows で作られた日本語ファイルを UTF-8 へ寄せる場面でしょう。
# Windows 由来の CSV を UTF-8 にする
iconv -f CP932 -t UTF-8 in.csv > out.csv
このとき変換元は SHIFT_JIS ではなく、CP932 を指定するほうが安全です。
理由は後半の「変換できない文字にぶつかったら」でまとめます。
いまのファイルが何のコードかを調べる
変換元が分からないときに頼りになるのが、file コマンドによる判定です。
$ file -i utf8.csv
utf8.csv: text/plain; charset=utf-8
$ file -i cp932.csv
cp932.csv: text/plain; charset=unknown-8bit
日本語の Shift_JIS 系は unknown-8bit としか出ないことが多く、file の結果だけで変換元を断定するのは危険。
候補を2つ3つ試して、読めたほうを採用するくらいの気持ちがちょうどよいと思います。
使えるコード名を一覧する
指定できる名前は環境によって違うため、迷ったら -l で並べてしまうのが早道。
iconv -l # 使えるコード名を全部出す
iconv -l | grep -i sjis # 候補を絞る
手元の GNU libiconv 1.18 では、別名をまとめた行が 198 行ぶん並びました。
変換できない文字にぶつかったら
変換先に存在しない文字があると、iconv はその位置で処理を止めます。
$ iconv -f UTF-8 -t SHIFT_JIS utf8.csv > out.sjis
iconv: utf8.csv:3:0: cannot convert
$ echo $?
1
3行目にあった「髙」(はしごだか)が SHIFT_JIS の範囲に無いために落ちた、というわけです。
-c で捨てる、//TRANSLIT で寄せる
-c を付けると、変換できない文字を捨てて残りを最後まで書き出してくれます。
$ iconv -c -f UTF-8 -t SHIFT_JIS utf8.csv > c.sjis
$ echo $?
1
$ iconv -f SHIFT_JIS -t UTF-8 c.sjis
名前,部署
山田,営業部
橋,経理部
「髙橋」から一文字だけ消えて「橋」になっている点に注目してください。
しかも -c を付けても終了コードは 1 のままなので、スクリプトで成否を判定しているなら落とし穴になります。
変換先に似た字があるなら、//TRANSLIT を付けて寄せるのも手です。
iconv -f UTF-8 -t 'SHIFT_JIS//TRANSLIT' in.csv > out.sjis
ただし手元の環境では「髙」に代替字が用意されておらず、この指定でも同じ行で止まりました。
//TRANSLIT は万能の保険ではない、という理解で使うのが安全でしょう。
SHIFT_JIS と CP932 は別物
今回いちばん腑に落ちたのが、この2つの差でした。
$ iconv -f UTF-8 -t SHIFT_JIS utf8.csv > /dev/null
iconv: utf8.csv:3:0: cannot convert # 終了コード 1
$ iconv -f UTF-8 -t CP932 utf8.csv > /dev/null
# 終了コード 0
同じファイルなのに、SHIFT_JIS では落ちて CP932 なら通る。
CP932 は Shift_JIS に機種依存文字を足した Windows 向けの拡張なので、Windows 由来の日本語ファイルは CP932 で扱うと事故がぐっと減ります。
よくある落とし穴
同じファイルへリダイレクトすると中身が消える
iconv -f CP932 -t UTF-8 same.csv > same.csv
# 実行後、same.csv は 0 バイトになる
シェルはリダイレクト先を先に空にしてから iconv を起動するため、読むべき中身がすでに残っていません。
別名で書き出してから置き換えるか、一時ファイルを挟むのが定石。
BOM は変換しても残る
$ iconv -f UTF-8 -t UTF-8 bom.csv | head -c 6 | xxd
00000000: efbb bfe5 908d ......
先頭の ef bb bf が BOM で、同じ UTF-8 どうしの変換では素通りしてしまうのです。
BOM の役割そのものは Unicode 公式の FAQ にまとまっているので、外してよいか迷ったら目を通すと判断が早まります。
最後に
iconv 自体は -f と -t を書くだけの小さなコマンドですが、実務でつまずくのは決まって「変換元をどう見極めるか」のほうでした。
Windows 由来なら CP932、Web からの取得なら UTF-8 と当たりを付け、file -i で裏を取る。
それでも落ちたときは、-c や //TRANSLIT へ逃げる前に どの文字が変換先に無いのかを1文字ずつ確かめるほうが、結局は早く片づきます。
なお本記事の実行例は、Windows の Git Bash 上の GNU libiconv 1.18・file 5.46・bash 5.2.37 で確認しました。
実装の詳細は GNU libiconv の公式ページ が一次情報になります。
文字コードではなく文字そのものを置き換えたいときは、tr の守備範囲になります。
以上です。











コメントを残す