file 命令详解与参数实测(Ubuntu 22.04)
file 命令逐参数实测详解:默认内容判型(文本/脚本/二进制/软链/目录)、-b、-i/--mime-type/--mime-encoding、-L、-z/-Z、-f 从标准输入批量读清单、-m 自定义魔数库与 -C 编译,附魔数判定原理解析,全部命令与回显在 Ubuntu 22.04(file-5.41)实测通过。
file 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 file 命令的每一个参数——默认内容判型(文本/脚本/二进制/软链/目录)、
-b精简输出、-i/--mime-type/--mime-encodingMIME 与编码探测、-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)。
六、参考链接
- file 官方项目主页:https://www.darwinsys.com/file/
- 问题反馈(--help 尾部标注):https://bugs.astron.com/
- 本机帮助:
file --help、man file(Ubuntu 22.04 内置) - 关联手册页:
man 5 magic(魔数规则文件格式)