【Linux】神奇的file文件命令及错误实例
推荐超级课程:
@TOC
你是否曾经好奇 file(1)
是如何工作的?
阅读完这篇文章后,你应该能完全理解 file
及其工作原理。
file命令
使用 file
工具非常简单。它就是 file file-name-1
。你也可以使用多个参数调用它。以下是在我的系统上运行它的几个例子。
$ file document.pdf
document.pdf: PDF 文档,版本 1.4
$ file image.jpg
image.jpg: JPEG 图像数据,Exif 标准:[TIFF 图像数据,大端,目录项=7 ...方向=左上,日期时间=2019:10:30 21:44:30,宽度=1740],基线,精度 8,2017x961,组件 3
$ file video.mp4
video.mp4: ISO 媒体,MP4 v2 [ISO 14496-14]
$ file notes.org
notes.org: UTF-8 Unicode 文本,具有非常长的行
$ file /dev/video0
/dev/video0: 字符特殊 (81/0)
你可以看到以下几点:
- 它可以处理任何类型的文件。
- 它尝试检查文件的内容(而不仅仅是扩展名)来确定文件类型。
- 它对文件格式有深入了解。它可以从文件本身中提取额外信息。你可以看到它理解 mp4 和 jpeg 文件的版本。
- 它了解特殊文件,例如设备。 但是,也有一些需要注意的地方。
file
在 shell 脚本中可能不会按预期工作。
$ file no-such-file
no-such-file: 无法打开 `no-such-file' (没有那个文件或目录)
$ echo $?
0
这个版本的 file
总是会以代码 0 退出。即使 file
无法识别文件。即使文件不存在。
2. 对于许多在 Unix/Linux 上不常见的格式,file
非常脆弱:
$ file Vagrantfile
Vagrantfile: HTML 文档,ASCII 文本
$ file microsoft.netcore.app.2.1.19.nupkg
microsoft.netcore.app.2.1.19.nupkg: Microsoft OOXML
是的,它真的认为一个 Vagrantfile
是 HTML 文档,而一个 NuGet 包文件
是 Office 文档!
那么,file
究竟是如何确定文件类型的呢?
像其他经典的 Unix 工具一样,file
有优秀的文档。man file
指出,file
按照以下顺序检查:
- 它检查文件是否是特殊类型的文件,例如设备。
- 它检查
magic(5)
数据库是否包含可以识别此文件类型的“魔术模式”。 - 它检查是否是文本文件。在这种情况下,
file
将尝试找出其他属性,例如语言、编码、行长度和行终止符类型(CR、LF 或 CRLF)。file
使用第一个成功的检查结果。如果这些检查都不成功,file
仅将文件类型报告为“数据”。 其中最有趣的是magic(5)
数据库选项。虽然其他检查相对静态,但你可以检查magic
数据库以了解file
的工作方式。你甚至可以手动修改数据库来修复错误[2]
magic命令
magic
数据库是一个纯文本文件。它通常位于 /usr/share/magic
。你可以在你最喜欢的编辑器中查看它。
/usr/share/magic
包含一系列测试和输出行。测试描述要查找的内容。如果测试匹配,则打印输出。
以下是一行的示例:
0 string Draw RISC OS Draw 文件数据
前 3 列是测试,最后一列是输出。 此行指定,如果文件位置 0 处的 string 与常量 Draw 匹配,则显示 RISC OS Draw 文件数据 作为文件类型。 为了使数据库维护人员的工作更容易,数据库支持嵌套测试。也就是说,测试可以说它仅在先前测试匹配时才适用。这由行开头的“>”指示。 以下是一个测试和嵌套测试的示例:
0 belong 0xcafebabe
>4 belong >30 编译的 Java 类数据,
这里的第一个测试是一个始终可以执行的测试。第二个测试包含一个测试,该测试仅在第一个测试成功时才应执行,这由行开头的“>”指示。
此示例中的第一个测试说:文件位置 0 处的 big-endian long 是否与常量 0xcafebabe
匹配。由于没有输出列,因此如果成功,它不会直接执行任何操作。
但是,如果测试成功,则运行嵌套测试。此示例中的嵌套测试检查文件位置 4 处的 big-endian long 是否 大于 30。如果是这样,则打印 编译的 Java 类数据。
man 5 magic
包含广泛的文档,涵盖了所有语法和选项,如果你想更详细地了解这些内容,可以查阅。
一个真实的错误
现在你对 file
和 magic
有了很好的了解,让我们看看如何使用这些知识来找出一个真实的“错误”。
作为本周发布 .NET Core 的一部分,我们发布管道中的某个工具标记了一个错误,说某个特定文件的类型已更改。错误如下所示:
file type changed for Microsoft.NETCore.App.Ref/3.1.0/data/PlatformManifest.txt:
-ASCII text
+Message Sequence Chart (chart)
错误告诉我们,文件类型已从 ASCII text 更改为 Message Sequence Chart (chart)。
这个错误看起来很奇怪。这是一个文本文件。扩展名是 .txt
。
内容看起来也像普通文本:
$ head Microsoft.NETCore.App.Ref/3.1.0/data/PlatformManifest.txt
mscorlib.dll|Microsoft.NETCore.App.Ref|4.0.0.0|4.700.19.56404
System.IO.Compression.Native.a|Microsoft.NETCore.App.Ref||0.0.0.0
System.IO.Compression.Native.so|Microsoft.NETCore.App.Ref||0.0.0.0
那么,为什么 file
说这是一个 Message Sequence Chart 呢?让我们看看是否能找到答案。
我们知道 file
使用什么算法。因此,我们将按照它的步骤进行分析。
首先,file
会检查它是否是一个特殊文件。我们可以使用 stat
来找出这是否是真的。
$ stat -c '%F' Microsoft.NETCore.App.Ref/3.1.0/data/PlatformManifest.txt
regular file
在这里,stat
确认这是一个常规文件。
接下来,file
将使用 magic
来猜测文件类型。
magic
数据库是否知道这个文件类型?
$ grep 'Message Sequence Chart' /usr/share/magic
0 string mscdocument Message Sequence Chart (document)
0 string msc Message Sequence Chart (chart)
0 string submsc Message Sequence Chart (subchart)
啊哈!它知道。
对于这一组测试,magic
检查位置 0 处的 string,如果它与 msc 匹配(或 mscdocument,或 submsc),则认为这是一个 Message Sequence Chart。
如果你还记得,文本文件的第一行是:
$ head Microsoft.NETCore.App.Ref/3.1.0/data/PlatformManifest.txt
mscorlib.dll|Microsoft.NETCore.App.Ref|4.0.0.0|4.700.19.56404
文件的前几个字节错误地与 msc 匹配。magic
和 file
看到匹配,并认为这是一个 Message Sequence Chart (chart)。
这显然是 file
(以及我们的工具)发出的误报。我们忽略了它。
总结
希望你现在对 file
和 magic
有了很好的了解。你也有了一个很好的起点,可以开始使用和调试这些工具,以防你以后需要。
- 其他资源
结语
file
和 magic
是强大的工具,可以帮助你了解文件类型和内容。通过学习它们的工作原理,你可以更有效地使用它们并解决可能出现的任何问题。