file 命令详解与参数实测(Ubuntu 22.04)

file 命令逐参数实测详解:默认内容判型(文本/脚本/二进制/软链/目录)、-b、-i/--mime-type/--mime-encoding、-L、-z/-Z、-f 从标准输入批量读清单、-m 自定义魔数库与 -C 编译,附魔数判定原理解析,全部命令与回显在 Ubuntu 22.04(file-5.41)实测通过。

Linux命令Linux系统UbuntuUbuntu 22.04命令行文件管理2026/10/15

file 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 file 命令的每一个参数——默认内容判型(文本/脚本/二进制/软链/目录)、-b 精简输出、-i/--mime-type/--mime-encoding MIME 与编码探测、-L 跟随软链、-z/-Z 窥探压缩包、-f 从标准输入批量读文件名、-m/-C 自定义魔数库,并用实测解析魔数判定原理,全部命令与回显已在 Ubuntu 22.04(file-5.41)实测通过。

一、环境信息

本篇所有命令与回显均在以下环境实测采集,读者在同等版本环境可逐条复现。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • file 版本:file-5.41(file --version 实测为准),软件包版本 1:5.41-3ubuntu0.1,Ubuntu 22.04 预装
  • 魔数数据库:file --version 实测显示 magic file from /etc/magic:/usr/share/misc/magic
  • 演示目录:/root/demo/file/
  • 测试数据:note.txt(普通文本文件)、demo.sh(可执行脚本)、echo.bin(复制 /bin/echo 得到的 ELF 二进制文件)、fake.png(只写入 PNG 8 字节签名的伪图片)、note.lnk(软链接)、gzsrc.txt 与 gzsrc.txt.gz(压缩演示)、subdir/(目录)

二、命令概览

file 的职责是按文件内容判定类型:读取文件头部字节,与魔数数据库中的特征规则比对,给出人类可读的类型描述。它不看扩展名——把任意文件改名成 .jpg 也不会被骗过,这是它成为脚本类型校验标配的原因。

2.1 语法与测试数据准备

file 的语法为 file [OPTION...] [FILE...](源自 --help 原文),常用形态是 file 文件 看类型、file -b --mime-type 文件 在脚本里取 MIME 值。先准备一套覆盖典型形态的演示数据:

mkdir -p /root/demo/file/subdir
printf 'hello file\nthis is plain text\n' > /root/demo/file/note.txt
printf '#!/bin/bash\necho "demo script"\n' > /root/demo/file/demo.sh
chmod +x /root/demo/file/demo.sh
cp /bin/echo /root/demo/file/echo.bin
printf '\x89PNG\r\n\x1a\n' > /root/demo/file/fake.png
ln -s /root/demo/file/note.txt /root/demo/file/note.lnk
printf 'gzip me\ncontent line\n' > /root/demo/file/gzsrc.txt
gzip -c /root/demo/file/gzsrc.txt > /root/demo/file/gzsrc.txt.gz

其中 fake.png 只写入了 PNG 的 8 字节签名(\x89PNG\r\n\x1a\n),用于演示魔数判定"认字节不认后缀"的特性。验证数据就绪:

$ ls -l /root/demo/file
total 60
-rwxr-xr-x 1 root root    31 Oct 15 06:28 demo.sh
-rwxr-xr-x 1 root root 35128 Oct 15 06:28 echo.bin
-rw-r--r-- 1 root root     8 Oct 15 06:28 fake.png
-rw-r--r-- 1 root root    21 Oct 15 06:28 gzsrc.txt
-rw-r--r-- 1 root root    51 Oct 15 06:28 gzsrc.txt.gz
lrwxrwxrwx 1 root root    24 Oct 15 06:28 note.lnk -> /root/demo/file/note.txt
-rw-r--r-- 1 root root    30 Oct 15 06:28 note.txt
drwxr-xr-x 2 root root  4096 Oct 15 06:28 subdir

2.2 --help 全量回显

file --help 输出全部参数清单(实测原样保留,可作为参数速查):

Usage: file [OPTION...] [FILE...]
Determine type of FILEs.

      --help                 display this help and exit
  -v, --version              output version information and exit
  -m, --magic-file LIST      use LIST as a colon-separated list of magic
                               number files
  -z, --uncompress           try to look inside compressed files
  -Z, --uncompress-noreport  only print the contents of compressed files
  -b, --brief                do not prepend filenames to output lines
  -c, --checking-printout    print the parsed form of the magic file, use in
                               conjunction with -m to debug a new magic file
                               before installing it
  -e, --exclude TEST         exclude TEST from the list of test to be
                               performed for file. Valid tests are:
                               apptype, ascii, cdf, compress, csv, elf,
                               encoding, soft, tar, json, text,
                               tokens
      --exclude-quiet TEST         like exclude, but ignore unknown tests
  -f, --files-from FILE      read the filenames to be examined from FILE
  -F, --separator STRING     use string as separator instead of `:'
  -i, --mime                 output MIME type strings (--mime-type and
                               --mime-encoding)
      --apple                output the Apple CREATOR/TYPE
      --extension            output a slash-separated list of extensions
      --mime-type            output the MIME type
      --mime-encoding        output the MIME encoding
  -k, --keep-going           don't stop at the first match
  -l, --list                 list magic strength
  -L, --dereference          follow symlinks (default if POSIXLY_CORRECT is set)
  -h, --no-dereference       don't follow symlinks (default if POSIXLY_CORRECT is not set) (default)
  -n, --no-buffer            do not buffer output
  -N, --no-pad               do not pad output
  -0, --print0               terminate filenames with ASCII NUL
  -p, --preserve-date        preserve access times on files
  -P, --parameter            set file engine parameter limits
                                   bytes 1048576 max bytes to look inside file
                               elf_notes     256 max ELF notes processed
                               elf_phnum    2048 max ELF prog sections processed
                               elf_shnum   32768 max ELF sections processed
                                encoding   65536 max bytes to scan for encoding
                                   indir      50 recursion limit for indirection
                                    name      50 use limit for name/use magic
                                   regex    8192 length limit for REGEX searches
  -r, --raw                  don't translate unprintable chars to \ooo
  -s, --special-files        treat special (block/char devices) files as
                             ordinary ones
  -S, --no-sandbox           disable system call sandboxing
  -C, --compile              compile file specified by -m
  -d, --debug                print debugging messages

Report bugs to https://bugs.astron.com/

💡 说明:-L/-h 的帮助原文注明了软链跟随的默认规则——未设置 POSIXLY_CORRECT 时默认不跟随(-h 为 default),实测见 3.6。-P bytes 默认 1048576,即 file 默认只检查文件前 1 MB 内容。

2.3 版本确认

$ file --version | head -1
file-5.41
$ file --version
file-5.41
magic file from /etc/magic:/usr/share/misc/magic

版本为 file-5.41;第二行直接给出魔数数据库路径 /etc/magic:/usr/share/misc/magic(冒号分隔多个候选)。再核对软件包版本:

$ dpkg -l file | tail -1
ii  file           1:5.41-3ubuntu0.1 amd64        Recognize the type of data in a file using "magic" numbers

三、参数逐项实测

本章对 file 的每个参数逐一实测:先看默认判型对五类对象分别给出什么结论,再依次验证输出控制、MIME、软链、压缩、批量清单与自定义魔数库。每条命令都给出真实回显与要点解读。

3.1 默认判型:文本、脚本、二进制、软链、目录

不带参数,file 对每类对象给出不同的类型描述:

$ file /root/demo/file/note.txt
/root/demo/file/note.txt: ASCII text
$ file /root/demo/file/demo.sh
/root/demo/file/demo.sh: Bourne-Again shell script, ASCII text executable
$ file /root/demo/file/echo.bin
/root/demo/file/echo.bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=05fcea56aa5e9ab4eab8bb1294538ad832b2d7d5, for GNU/Linux 3.2.0, stripped
$ file /root/demo/file/note.lnk
/root/demo/file/note.lnk: symbolic link to /root/demo/file/note.txt
$ file /root/demo/file/subdir
/root/demo/file/subdir: directory
$ file /root/demo/file/fake.png
/root/demo/file/fake.png: data

逐条解读:纯文本报 ASCII text;脚本除内容外还识别出解释器归属(Bourne-Again shell script);ELF 二进制给出架构、链接方式、解释器路径、BuildID 等远超"是二进制"的信息量;软链报出指向目标;目录直接报 directory。最值得注意的是 fake.png——扩展名是 .png,结果却只报 data:它只有 PNG 的 8 字节签名,缺少后续 IHDR 等必备结构,魔数规则未能命中确定类型。这正说明 file 判定只依据内容、不看扩展名。

💡 技术拓展:判定文件类型常见三类思路,对比——

方法原理局限
扩展名映射按文件名后缀查表(Windows 惯例)改个名就失效,Linux 不强制后缀
魔数比对读文件头部字节与特征库规则比对(file 的主判定)特征库未收录的类型只能报 data
内容启发式统计可打印字符比例、探测编码(file 的兜底)只能粗分 text/binary,难细分格式

file 实际采用「魔数优先、编码启发式兜底」的组合:魔数库命中则给出详细描述,未命中再按内容报 ASCII text/data 等,fake.png 就是"签名残留但规则未命中"的典型中间态。

3.2 批量判型与对齐输出

file 支持一次传多个文件,多文件输出时自动补空格使冒号对齐,便于阅读:

$ file /root/demo/file/*
/root/demo/file/demo.sh:      Bourne-Again shell script, ASCII text executable
/root/demo/file/echo.bin:     ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=05fcea56aa5e9ab4eab8bb1294538ad832b2d7d5, for GNU/Linux 3.2.0, stripped
/root/demo/file/fake.png:     data
/root/demo/file/gzsrc.txt:    ASCII text
/root/demo/file/gzsrc.txt.gz: gzip compressed data, was "gzsrc.txt", last modified: Thu Oct 15 06:28:18 2026, from Unix, original size modulo 2^32 21
/root/demo/file/note.lnk:     symbolic link to /root/demo/file/note.txt
/root/demo/file/note.txt:     ASCII text
/root/demo/file/subdir:       directory

gzip 条目顺带展示了 file 对压缩文件的默认能力:不解压也能报出原始文件名、压缩时间与原始大小(21 字节)。想要"不探压缩包内部"的纯头部判型即此默认行为,深入内部用 -z(见 3.7)。

3.3 -b(--brief):省略文件名前缀

-b 只输出类型描述本身,便于脚本直接取值:

$ file -b /root/demo/file/note.txt
ASCII text
$ file -b /root/demo/file/echo.bin
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=05fcea56aa5e9ab4eab8bb1294538ad832b2d7d5, for GNU/Linux 3.2.0, stripped

对比 3.1 的同名命令,区别仅在去掉了 路径: 前缀。脚本里做字符串比较时,-b 免去手工裁剪。

3.4 -i(--mime)与 --mime-type:MIME 输出

-i 把判定结果转成 MIME 类型; charset=编码 形态:

$ file -i /root/demo/file/note.txt
/root/demo/file/note.txt: text/plain; charset=us-ascii
$ file -i /root/demo/file/demo.sh
/root/demo/file/demo.sh: text/x-shellscript; charset=us-ascii
$ file -i /root/demo/file/echo.bin
/root/demo/file/echo.bin: application/x-pie-executable; charset=binary
$ file -b -i /root/demo/file/subdir
inode/directory; charset=binary

非文本对象(二进制、目录)的 charset 统一为 binary——它不是真实编码,只表示"非文本流"。只要 MIME 类型不要编码时用独立的 --mime-type:

$ file --mime-type /root/demo/file/note.txt
/root/demo/file/note.txt: text/plain
$ file --mime-type /root/demo/file/echo.bin
/root/demo/file/echo.bin: application/x-pie-executable

3.5 --mime-encoding:字符编码探测

--mime-encoding 单独输出编码结论,配 -b 可拿到裸值:

$ file --mime-encoding /root/demo/file/note.txt
/root/demo/file/note.txt: us-ascii
$ file -b --mime-encoding /root/demo/file/note.txt
us-ascii

处理多语言文本(判断是否 utf-8)或校验日志编码时用它;file 对编码的扫描范围由 -P encoding 参数控制(默认 65536 字节,见 --help)。

3.6 -L(--dereference)与 -h(--no-dereference):软链跟随控制

默认(等价 -h)不跟随软链,报的是链接本身;-L 跟随软链,报目标文件的类型:

$ file /root/demo/file/note.lnk
/root/demo/file/note.lnk: symbolic link to /root/demo/file/note.txt
$ file -L /root/demo/file/note.lnk
/root/demo/file/note.lnk: ASCII text
$ file -b -L /root/demo/file/note.lnk
ASCII text
$ file -h /root/demo/file/note.lnk
/root/demo/file/note.lnk: symbolic link to /root/demo/file/note.txt

-h 显式写出的效果与默认一致,适合在设置过 POSIXLY_CORRECT(此时默认会跟随)的脚本里固定语义。审计软链清单用默认,判断软链最终指向什么内容用 -L。

3.7 -z(--uncompress)与 -Z(--uncompress-noreport):窥探压缩包内部

先看压缩前后的对比:gzsrc.txt 是普通文本,其 gzip 压缩件默认只报压缩信息:

$ file /root/demo/file/gzsrc.txt
/root/demo/file/gzsrc.txt: ASCII text
$ file /root/demo/file/gzsrc.txt.gz
/root/demo/file/gzsrc.txt.gz: gzip compressed data, was "gzsrc.txt", last modified: Thu Oct 15 06:28:18 2026, from Unix, original size modulo 2^32 21

-z 会解压窥探内部,把"内容类型 + 压缩信息"一起报出:

$ file -z /root/demo/file/gzsrc.txt.gz
/root/demo/file/gzsrc.txt.gz: ASCII text (gzip compressed data, was "gzsrc.txt", last modified: Thu Oct 15 06:28:18 2026, from Unix)

-Z 与 -z 同样窥探内部,但不附加压缩信息括号,输出更干净:

$ file -Z /root/demo/file/gzsrc.txt.gz
/root/demo/file/gzsrc.txt.gz: ASCII text

三个结论对应三种需求:判"是不是压缩包"用默认,判"包里装的是什么"用 -z,脚本只取内容类型用 -Z。

3.8 -f(--files-from):从文件或标准输入读文件名清单

-f FILE 从指定文件逐行读取待判型清单;传 - 表示从标准输入读,可与管道串接:

$ printf '/root/demo/file/note.txt\n/root/demo/file/echo.bin\n/root/demo/file/subdir\n' | file -f -
/root/demo/file/note.txt:                        ASCII text
/root/demo/file/echo.bin:                        ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=05fcea56aa5e9ab4eab8bb1294538ad832b2d7d5, for GNU/Linux 3.2.0, stripped
/root/demo/file/subdir:                      directory

清单里的相对路径按 file 进程的当前工作目录解析,例如进入演示目录后直接把 ls 结果喂进去:

$ cd /root/demo/file && ls | file -f -
demo.sh:       Bourne-Again shell script, ASCII text executable
echo.bin:        ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=05fcea56aa5e9ab4eab8bb1294538ad832b2d7d5, for GNU/Linux 3.2.0, stripped
fake.png:        data
gzsrc.txt:         ASCII text
gzsrc.txt.gz:            gzip compressed data, was "gzsrc.txt", last modified: Thu Oct 15 06:28:18 2026, from Unix, original size modulo 2^32 21
note.lnk:        symbolic link to /root/demo/file/note.txt
note.txt:        ASCII text
subdir:      directory

这一形态让 file 能接在任何"产出文件名列表"的命令后面(find、git ls-files 等),比 xargs 拼接更能稳妥处理文件名。

3.9 魔数判定原理与自定义 magic:-m、-C、-l、-c

file 的判定核心是魔数数据库:库中每条规则描述"某偏移处出现某字节序列 ⇒ 该类型"。本环境实际加载的数据库由 2.3 的 file --version 给出(/etc/magic:/usr/share/misc/magic),/usr/share/misc 下是两个指向真实库文件的软链:

$ ls -l /usr/share/misc/
total 0
lrwxrwxrwx 1 root root 13 Sep 11  2023 magic -> ../file/magic
lrwxrwxrwx 1 root root 24 Sep 11  2023 magic.mgc -> ../../lib/file/magic.mgc

-m 可以指定自定义规则文件临时替换默认库。先写一条最简规则(0 偏移处出现字符串 DEMO123 则报自定义描述)并造一个命中文件:

printf '0\tstring\tDEMO123\tMy custom demo file\n' > /root/demo/file/my.magic
printf 'DEMO123 content here\n' > /root/demo/file/magic-demo.txt
$ file -m /root/demo/file/my.magic /root/demo/file/magic-demo.txt
/root/demo/file/magic-demo.txt: My custom demo file

自定义规则命中,输出整行变成规则里的描述文本。-C 把文本规则编译成二进制 .mgc(加载更快):

$ file -C -m /root/demo/file/my.magic

$ ls -l /root/demo/file/my.magic.mgc
ls: cannot access '/root/demo/file/my.magic.mgc': No such file or directory

注意这个常见误区:编译产物并不落在 magic 文件旁边,而是写在 file 进程的当前工作目录下(本环境工作目录为 /):

$ ls -l /my.magic.mgc
-rw-r--r-- 1 root root 752 Oct 15 06:32 /my.magic.mgc

编译产物同样可以直接喂给 -m,且对未命中规则的文件回落到常规文本判定:

$ file -m /my.magic.mgc /root/demo/file/magic-demo.txt
/root/demo/file/magic-demo.txt: My custom demo file
$ file -b -m /my.magic.mgc /root/demo/file/note.txt
ASCII text

-l 列出规则的匹配强度(strength,数值越高越优先),-c 打印规则被解析后的内部形态,都是调试自定义 magic 的工具:

$ file -l -m /root/demo/file/my.magic
unknown, 0: Warning: using regular magic file `/root/demo/file/my.magic'
Set 0:
Binary patterns:
Strength = 100@1: My custom demo file []
Text patterns:
Set 1:
Binary patterns:
Text patterns:
$ file -c -m /root/demo/file/my.magic | head -5
unknown, 0: Warning: using regular magic file `/root/demo/file/my.magic'
cont	offset	type	opcode	mask	value	desc
1: > 0 string,=DEMO123,"My custom demo file"]

验证完毕清理编译产物:

$ rm /my.magic.mgc

3.10 -e:排除指定测试项

-e TEST 从判定流程中剔除某类测试(可用值见 --help:apptype、ascii、cdf、compress、csv、elf、encoding、soft、tar、json、text、tokens)。排除 elf 测试后,ELF 深度解析(解释器、BuildID 等细节)不再执行,只余头部基础结论:

$ file -e elf /root/demo/file/echo.bin
/root/demo/file/echo.bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)

对比 3.1 的默认输出,尾部 dynamically linked、BuildID、for GNU/Linux、stripped 均消失。批量处理大量二进制且只关心大分类时,排除深度测试可显著提速。

3.11 输出控制:-F、-k、-n、-N、-0、-r、--apple、--extension

-F 自定义文件名与结论之间的分隔符(默认冒号):

$ file -F '|' /root/demo/file/note.txt
/root/demo/file/note.txt| ASCII text

-k 不在首条规则命中后停止,而是报告所有命中的规则;本例纯文本只有一条规则命中,输出与默认一致,差异只在多规则同时命中的文件上可见:

$ file -k /root/demo/file/note.txt
/root/demo/file/note.txt: ASCII text

-n 关闭输出缓冲(逐条实时刷出,适合管道消费),-N 取消多文件时的文件名补齐对齐,两者对单文件输出的可见内容无影响:

$ file -n /root/demo/file/note.txt
/root/demo/file/note.txt: ASCII text
$ file -N /root/demo/file/note.txt
/root/demo/file/note.txt: ASCII text

-0 用 NUL 字节(\0)替换冒号分隔符,配合 xxd 可见文件名后紧跟 00,供 xargs -0 安全消费:

$ file -0 /root/demo/file/note.txt | xxd | head -4
00000000: 2f72 6f6f 742f 6465 6d6f 2f66 696c 652f  /root/demo/file/
00000010: 6e6f 7465 2e74 7874 003a 2041 5343 4949  note.txt.: ASCII
00000020: 2074 6578 740a                            text.

-r 不把不可打印字符转义成 \ooo 八进制形式(对含怪字符的文件名才有可见差异),本例输出不变:

$ file -r /root/demo/file/note.txt
/root/demo/file/note.txt: ASCII text

--apple 输出 Apple CREATOR/TYPE 四字节标记,--extension 输出与类型对应的推荐扩展名;本环境的魔数库未为相关条目标注 Apple 类型与扩展名,两者分别返回 UNKNUNKN 与 ???(未知),属正常的"库未标注"结果:

$ file --apple /root/demo/file/note.txt
/root/demo/file/note.txt: UNKNUNKN
$ file --extension /root/demo/file/note.txt
/root/demo/file/note.txt: ???
$ file --extension /root/demo/file/echo.bin
/root/demo/file/echo.bin: ???

3.12 特殊文件与扫描控制:-s、-p、-P、-S、-d

设备等特殊文件默认只报设备类别,-s 把它当普通文件读取内容再判型——/dev/zero 读出来是无限零字节,判为 data:

$ file /dev/zero
/dev/zero: character special (1/5)
$ file -s /dev/zero
/dev/zero: data

-p 判型后把文件的访问时间恢复原样(读取行为会更新 atime,此参数抹掉这一痕迹),适用于不想扰动时间戳的审计场景,输出内容本身无差异:

$ file -p /root/demo/file/note.txt
/root/demo/file/note.txt: ASCII text

-P 调整判定引擎的扫描上限(各参数默认值见 --help,如 bytes 默认 1048576)。把检查字节数压到 64 后,ELF 判定只剩 64 字节头部内的结论,stripped 等需深入扫描的细节消失:

$ file -P bytes=64 /root/demo/file/echo.bin
/root/demo/file/echo.bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)

-S 关闭 file 自带的系统调用沙箱(个别受限环境里沙箱会导致判型失败,用此参数绕过),本例输出不变:

$ file -S /root/demo/file/note.txt
/root/demo/file/note.txt: ASCII text

-d 输出判定过程的调试明细:先逐类尝试压缩/tar/json/cdf/elf 等入口,再逐条比对魔数规则。完整输出很长(本例已以 head -12 截取),此处再节选实测前 8 行:

$ file -d /root/demo/file/magic-demo.txt 2>&1 | head -12
[try zmagic 0]
[try tar 0]
[try json 0]
[try csv 0]
[try cdf 0]
[try elf 0]
bb=[0x7f3d92f72010,21,0], 0 [b=0x7f3d92f72010,21,0], [o=0, c=0]
mget(type=5, flag=0x20, offset=0, o=0, nbytes=21, il=0, nc=0)

节选中可见判定顺序(zmagic、tar、json、csv、cdf、elf 依次尝试)与逐条魔数规则的匹配过程,排疑自定义 magic 不生效时用它最快。

3.13 目标不存在时的行为与退出码

对不存在的路径,file 在输出行内报 cannot open——但整体退出码仍是 0:

$ file /root/demo/stat/nosuch; echo exit=$?
/root/demo/stat/nosuch: cannot open `/root/demo/stat/nosuch' (No such file or directory)
exit=0

这一点与多数命令不同:file 把"打不开"视为一种判定结果而非致命错误。脚本里判断文件是否存在要靠 test -e,不能依赖 file 的退出码。

四、实战示例

以下示例均可独立执行,覆盖系统巡检与脚本校验两类高频场景。

4.1 系统命令与配置文件判型

一条命令看清三类系统路径的真实身份:

$ file /bin/sh /bin/bash /etc/passwd
/bin/sh:     symbolic link to dash
/bin/bash:   ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=7a6408ba82a2d86dd98f1f75ac8edcb695f6fd60, for GNU/Linux 3.2.0, stripped
/etc/passwd: ASCII text

/bin/sh 原来是指向 dash 的软链(Ubuntu 的默认 shell 是 dash 而非 bash),/bin/bash 是 ELF 可执行,/etc/passwd 是纯文本——排查"脚本解释器行为差异"这类问题时,先判型再定位。

4.2 上传文件 MIME 白名单校验

服务端校验用户上传文件时,用 MIME 类型做白名单,绕过伪造扩展名的攻击面:

$ file -b --mime-type /root/demo/file/*
text/x-shellscript
application/x-pie-executable
application/octet-stream
text/plain
application/gzip
text/plain
text/plain
inode/symlink
text/plain
inode/directory

输出与通配展开顺序一一对应:脚本是 text/x-shellscript、ELF 是 application/x-pie-executable、只有 PNG 签名的 fake.png 是 application/octet-stream(不认识的二进制流)、软链是 inode/symlink。脚本中配合 case 语句只放行预期 MIME 即可。

4.3 批量筛出目录下所有文本文件

find 产出文件清单、file 逐个判型,两步合并成一条命令:

$ find /root/demo/file -name '*.txt' -exec file {} \;
/root/demo/file/magic-demo.txt: ASCII text
/root/demo/file/note.txt: ASCII text
/root/demo/file/gzsrc.txt: ASCII text

-exec file {} \; 对 find 命中的每个文件单独调用 file;清单很大时改用 find 的 -print0 配合 file 的 -f - -0(NUL 分隔)更稳妥,相关参数见 3.8 与 3.11。

五、注意事项与常见问题

Q1:把文本改名成 .jpg 后 file 会认成图片吗? 不会。file 只读内容、不看扩展名,改名后仍报文本类型;反过来只有 PNG 签名、结构不完整的 fake.png 也只会报 data(见 3.1)。

Q2:file 对不存在的文件返回成功(退出码 0),脚本里怎么防? 这是设计行为:cannot open 被当作一种判定结果写入输出。存在性判断交给 test -e,file 只负责判型(见 3.13)。

Q3:-i 输出末尾的 charset=binary 是编码吗? 不是。它只表示"非文本流";文本对象才给出真实编码(us-ascii、utf-8 等),见 3.4。

Q4:--extension 为什么输出 ???? 魔数库条目自带扩展名标注时才有值,本环境的库未标注,返回 ??? 表示未知;这是正常的库数据问题,不是命令故障(见 3.11)。

Q5:-L 与默认行为到底差在哪? 默认不跟随软链、报链接本身(除非环境变量 POSIXLY_CORRECT 已设置);-L 强制跟随,报目标文件类型;-h 可显式固定不跟随语义(见 3.6)。

Q6:-z 和 -Z 怎么选? 都窥探压缩包内部:-z 输出"内容类型 + 压缩信息",-Z 只输出内容类型,脚本取值用后者更干净(见 3.7)。

Q7:大文件判型会整文件扫描吗? 不会。默认只检查前 1048576 字节(-P bytes 的默认值),且 -e 可剔除 elf 等深度测试进一步提速;超大文件判定结果只反映头部特征(见 3.10、3.12)。

Q8:想让 file 识别自有格式怎么办? 编写自定义 magic 规则文件配合 -m 使用;正式环境用 -C 编译成 .mgc 加载更快——注意编译产物落在进程工作目录而非 magic 文件旁(见 3.9)。

六、参考链接