file コマンド入門 - 拡張子に頼らずファイル種別を見抜く

file コマンド入門 - 拡張子に頼らずファイル種別を見抜く

この記事でわかること

  • file コマンドが 拡張子ではなく中身を見て ファイル種別を判定する仕組み
  • 拡張子を書き換えても file本当の正体を見抜く 理由
  • file -iMIME タイプ を調べる方法
  • -b や圧縮ファイル対応など よく使うオプション

結論(先に要点)

  • file ファイル名 で、そのファイルが何者かを一発で判定できる
  • 判断材料は 拡張子ではなく中身の先頭バイト列(マジックナンバー)
  • 拡張子を .txt に変えても、中身が JPEG なら file は JPEG と答える

前提(対象環境)

  • OS: Ubuntu / 一般的な Linux
  • file は標準でインストール済み(coreutils とは別パッケージ file

1. file コマンドとは?拡張子と何が違う?

結論: file はファイルの中身を読んで種別を判定するコマンド。拡張子という「自己申告」ではなく、実体で判断する。

リナ: ファイルの種類って、photo.jpg みたいに拡張子を見ればわかりますよね?
ライニー先輩: 普段はそれでいい。でも拡張子は「自己申告」なんだ。名前を変えれば中身と食い違うこともある。file は中身そのものを読んで判定するコマンドだよ。
リナ: 中身を読む…?ファイルを開かないと中身ってわからないんじゃ?
ライニー先輩: 多くのファイル形式は、先頭の数バイトに「自分は何者か」を示す目印を持っているんだ。これを マジックナンバー と呼ぶ。file はそこを読んでいる。
file report.pdf
report.pdf: PDF document, version 1.7

file の判定は /usr/share/misc/magic(コンパイル済みは magic.mgc)に登録されたパターン集(libmagic)に基づく。何千もの形式の目印が登録されている。

2. なぜ拡張子は当てにならないのか?

結論: 拡張子は名前の一部にすぎず、中身を保証しない。file は中身で判断するため、偽装された拡張子に騙されない。

リナ: 拡張子が当てにならないって、どういう場面で困るんですか?
ライニー先輩: たとえば画像ファイルの名前を間違えて .txt にしてしまった場合。Windows からもらったファイルで拡張子が消えている場合もある。そんなとき中身を確認したいよね。
リナ: 試してみます。画像の名前を .txt に変えてみますね。
mv penguin.jpg penguin.txt
file penguin.txt
penguin.txt: JPEG image data, JFIF standard 1.01, resolution (DPI), 72x72
リナ: 名前は .txt なのに、ちゃんと JPEG だって見抜いた!
ライニー先輩: そう。名前ではなく中身を見ているから、こうなる。逆に拡張子のないファイルでも種別がわかるんだ。

3. file コマンドの基本的な使い方は?

結論: file ファイル名 が基本形。複数指定やワイルドカードで、まとめて種別を確認できる。

リナ: 基本の使い方を教えてください。
ライニー先輩: ファイル名を渡すだけ。複数並べてもいいし、* でまとめても判定してくれるよ。
file notes.txt
file *
notes.txt: ASCII text
archive.tar.gz: gzip compressed data, original size modulo 2^32 10240
script.sh:  Bourne-Again shell script, ASCII text executable
image.png:  PNG image data, 800 x 600, 8-bit/color RGBA, non-interlaced

ディレクトリやシンボリックリンク、空ファイルもそれぞれ directory / symbolic link to ... / empty と表示される。

4. MIME タイプを調べるには?(-i)

結論: file -itext/plain; charset=utf-8 のような MIME タイプと文字コードを取得できる。スクリプトでの判定に向く。

リナ: ときどき見る text/plain みたいな表記は、file で出せますか?
ライニー先輩: -i--mime)を付けると MIME タイプ形式で出る。プログラムから扱いやすい形だよ。文字コード(charset)も一緒に表示される。
file -i notes.txt
file -i report.pdf
notes.txt: text/plain; charset=utf-8
report.pdf: application/pdf; charset=binary

MIME タイプだけ・文字コードだけが欲しいときは --mime-type / --mime-encoding を使う。

file --mime-type photo.png
photo.png: image/png

5. よく使うオプションは?

結論: -b(ファイル名省略)、-L(リンク先を辿る)、-z(圧縮の中身)、-s(デバイスファイル)あたりを押さえれば十分。

オプション 意味
-b / --brief ファイル名を出力せず種別だけ表示
-i / --mime MIME タイプ形式で出力
-L シンボリックリンクのリンク先を判定
-z 圧縮ファイルの中身まで覗いて判定
-s ブロック / キャラクタデバイスを読んで判定
-k 最初の一致で止めず候補を出し続ける
リナ: -b はどんなときに便利ですか?
ライニー先輩: 出力をスクリプトで受け取るとき。ファイル名が前に付くと邪魔なので、種別だけ欲しいなら -b が楽だよ。
file -b script.sh
Bourne-Again shell script, ASCII text executable

-z を使うと .gz などを展開せずに「中身が何の圧縮か+元ファイルの種別」まで確認できる。

file -z logs.tar.gz

6. 実務ではどんな場面で使う?

結論: ダウンロードファイルの正体確認、テキストかバイナリかの判別、展開前のアーカイブ確認などで活躍する。

リナ: 実際の作業だと、どこで使うんでしょう?
ライニー先輩: たとえば curl で落としたファイルが本当に目的のものか確認するとき。HTML のエラーページが落ちてきていないか file で一発チェックできる。
curl -sL https://example.com/app.tar.gz -o app.tar.gz
file app.tar.gz
app.tar.gz: gzip compressed data, ...

ここで HTML document と出たら、アーカイブではなくエラーページを落としている。展開前に気づけるのが file の価値。

7. つまずきやすいポイントは?

結論: file の判定は推定であり 100% ではない。シンボリックリンクは -L、デバイスファイルは -s を忘れると意図と違う結果になる。

リナ: シンボリックリンクを file したら、リンクそのものの情報しか出ませんでした。
ライニー先輩: デフォルトはリンク自体を見るからね。リンク先の実体を判定したいときは -L を付ける。
file -L /usr/bin/python3

8. ミニ課題

結論: 手を動かすと定着する。拡張子を変えても file が見抜くことを自分で確かめよう。

やってみよう

  1. 適当なテキストを作る: echo "hello" > sample.txt
  2. 種別を確認: file sample.txt
  3. 名前を変える: mv sample.txt sample.bin
  4. もう一度判定: file sample.bin —— 拡張子が変わっても結果はどうなる?
解答例

sample.bin: ASCII text と表示される。中身は変わっていないので、file の判定(ASCII text)も変わらない。拡張子に依存していない証拠。

次に読む