「.txt のはずなのに、開いたら画面が文字化けの砂嵐になった」
そんな場面に出くわしたこと、一度はあるのではないでしょうか。
拡張子は人間が付けたただのラベルにすぎません。
中身とラベルが食い違っていても、OS はとくに怒らないのです。
そこで頼りになるのが file コマンド。
この記事では、file を「中身の形式を見る」「表示を削る」「文字コードを見る」の3つに絞って整理しました。
手元の確認は Windows の Git Bash に同梱された file 5.46 で行っています。
fileは拡張子ではなく中身を読む
file が種類を判定する手がかりは、ファイルの先頭に置かれた数バイトの並び。
この目印はマジックナンバーと呼ばれ、PNG なら 89 50 4E 47、ZIP なら 50 4B のように形式ごとに決まっているのです。
つまりfile が見ているのはファイル名ではなく、中身の先頭。
どれだけ拡張子を偽っても、中身のほうは嘘をつきません。
実際に、1×1 の PNG を notes.txt という名前でコピーして試してみました。
$ file notes.txt
notes.txt: PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced
拡張子が .txt でも、PNG だと即座に見抜いてくれます。
しかも画像サイズや色深度まで読み取ってくれるので、壊れているかどうかの当たりも付けやすいですね。
まず覚える3つ:そのまま・-b・-i
file の使い方は、この3つで大半の場面をしのげるはず。
1. そのまま渡す(種類を知る)
引数にファイルを並べるだけで、1行1ファイルの一覧が返ります。
$ file utf8.txt real.zip run.sh sub
utf8.txt: ASCII text
real.zip: Zip archive data, made by v2.0, extract using at least v2.0, ...
run.sh: Bourne-Again shell script, ASCII text executable
sub: directory
ディレクトリなら directory、シェルスクリプトなら先頭のシェバンまで読んで「Bourne-Again shell script」と答えてくれる親切さ。
なお、正体をつかめないバイナリは data という素っ気ない一語になります。
2. -b でファイル名を消す
スクリプトの中で結果を使うときは、行頭の「ファイル名:」がむしろ邪魔になりがち。
-b(brief)を付けると、判定結果だけが出力されます。
$ file -b tiny.png
PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced
条件分岐へ流し込む前処理としては、これがいちばん扱いやすい形なのです。
3. -i でMIMEタイプを見る
人間向けの説明文ではなく、機械で扱える形が欲しいときに使うのが -i です。
$ file -i tiny.png utf8ja.txt
tiny.png: image/png; charset=binary
utf8ja.txt: text/plain; charset=utf-8
image/png のような MIME タイプなら、判定文字列がバージョンで揺れる心配も小さくなります。
形式だけが欲しいときは --mime-type を付けると、image/png の1語まで削れますよ。
文字コードの当たりを付ける
file の地味に嬉しい点が、テキストの文字コードまで一緒に見てくれるところ。
同じ「日本語のテキストです」を UTF-8 と Shift_JIS で保存し、並べて比べてみます。
$ file utf8ja.txt sjis.txt bom.csv
utf8ja.txt: Unicode text, UTF-8 text
sjis.txt: Non-ISO extended-ASCII text
bom.csv: Unicode text, UTF-8 (with BOM) text, with CRLF line terminators
UTF-8 は名指しで当ててくれる一方、Shift_JIS は「Non-ISO extended-ASCII text」という曖昧な答え。
日本語の文字コードを断定する用途には向いていない、と割り切っておくのが安全です。
それでも BOM の有無や改行コードまで教えてくれるので、文字化けの原因を絞り込む一手目としては十分に強力。
3つ目の bom.csv では、BOM 付き UTF-8 であることと CRLF 改行であることが同時に読み取れています。
「開けない CSV」を渡されたとき、この1行だけで犯人の目星が付くこともあるのです。
文字コードそのものの仕組みは、別記事で整理しました。
まとめて調べる・つまずきやすいところ
ディレクトリを丸ごと調べたいときは、find と組み合わせます。
file 自体に再帰オプションが無いので、ここは分業になるわけですね。
$ find . -type f -print0 | xargs -0 file | grep -i image
./notes.txt: PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced
./tiny.png: PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced
grep で絞れば、「この中に画像が紛れていないか」を一発で洗い出せます。
パイプで受け取りたいときは、ファイル名の代わりにハイフンを置くだけ。
$ cat tiny.png | file -
/dev/stdin: PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced
つまずきやすいのは、判定文字列が環境やバージョンによって微妙に変わる点でしょう。
スクリプトで分岐させるなら、説明文そのものではなく --mime-type の出力を条件にするほうが壊れにくいのです。
もう一歩踏み込んで、先頭のバイト列を自分の目で確かめたくなったら od や xxd の出番になります。
逆に、ファイルではなくコマンドの正体を知りたい場面もあるはず。
最後に
file は、拡張子という自己申告を疑うためのコマンドです。
そのまま渡して種類を知り、-b で表示を削り、-i で MIME を取り出す。
この3手を覚えておくだけで、「開く前にひとまず確かめる」という癖が身につきます。
正体不明のファイルを渡されたときこそ、まず file に一声かけてみてください。
以上です。











コメントを残す