在 Linux 中确定文件的用户视角“类型”的最彻底方法?

在 Linux 中确定文件的用户视角“类型”的最彻底方法?

我正在寻找(在文件管理器类型的应用程序中)提供最相关的自然语言描述,说明目录中的每个文件是什么类型的文件。似乎有几种命令行机制可以完成部分工作,并且具有重叠的优势。让我们看看他们在几个相对普通的测试用例上的行为。 (-b 选项只是为了在这些示例中不重复打印文件名。)

  1. ssh-keygen 为我生成的公钥(它选择了文件名):
~> file -b xgl_ed25519.pub
OpenSSH ED25519 public key
~> mimetype -d -b xgl_ed25519.pub
Microsoft Publisher document
~> mimetype -d -M -b xgl_ed25519.pub # -M = "ignore extension"
plain text document

文件是正确的,mimetype 非常混乱,mimetype -M 是正确的,但毫无帮助地不具体。

  1. 手写的 Markdown 文件:
Notes> file -b servers.md
Nim source code, Unicode text, UTF-8 text, with very long lines (5244)
Notes> mimetype -d -b servers.md
Markdown document
Notes> mimetype -d -M -b servers.md
plain text document

文件非常混乱,mimetype 是正确的,mimetype -M 也是正确的,但帮助不大。

  1. 我碰巧收到一个带有非标准扩展名的 JPEG 文件:
GVIP> file -b example.img
JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 960x720, components 3
GVIP> GVIP> mimetype -d -b example.img
Raw disk image
GVIP> mimetype -d -M -b example.img
JPEG image

这里的文件是正确的,但是超级啰嗦,mimetype 很混乱,而 mimetype -M 是正确的。

这些示例的要点是,我相对经常遇到不同的示例,其中每种方法都会产生我想呈现给用户的最佳/最实用的答案。但是,从用户角度确定文件的良好特征肯定是一个受到广泛关注的问题。毕竟,大多数文件管理器都有一个“类型”字段。 (我认识到还有哑剧打字机,例如file -imimetype没有标志,和xdg-mime query filetype,但哑剧类型相当冗长并且不太用户友好;我正在寻找自然语言描述,而且仍然存在知道是否或者不信任该扩展。)

所以问题是,获得文件类型的有用/准确/具体特征的最可靠方法是什么?我宁愿不拼凑出某种逻辑,例如“尝试file,如果它产生一些简短而具体的内容,就这样做,但如果没有,则比较有mimetype和没有-M标志,并根据结果决定信任哪个:如果答案没有 -M 与 -M 兼容但比 -M 更具体,使用它,否则使用 -M 答案”。 (坦率地说,我根本不想使用“mimetype”,因为它引入了对或多或少过时的 Perl 语言的依赖。是否有更现代的方法来访问 mime 类型数据库中的描述? )

无论如何,对于一般的文件特征问题,我不限于命令行解决方案;如果有一种相对常见的当前语言和一个对此有好处的库,我也可能会使用它。感谢您的任何指导。

答案1

我永远不会接受这个答案,我只是想我应该分享我目前正在使用的临时令人厌恶的东西。它很慢而且很粗糙,但似乎产生了非常有用的结果。我喜欢对于零长度文件,它会生成“空”文件类型;我还没有见过任何文件管理器可以做到这一点。

由于它是一个快速原型,因此采用 xonsh 脚本的形式。如果您不熟悉 xonsh,在这种情况下,您可以假设它是 python,具有非常方便的语法$(blah bloo)来捕获 command 的输出blah bloo

#!/usr/bin/env xonsh
import re

filesez = $(file -b $ARG1)
filesez = filesez.strip()

# file is very good at detecting scripts:
script = re.search(r'\w*\s*script', filesez)
if script:
   print(script.group())
   exit(0)

# If file said anything complicated, we'll try mimetype
punctuation = re.search(r'[,;]', filesez)
# For text files, assume the extension is right
trust = (filesez == 'ASCII text')
if not (punctuation or trust):
   print(filesez)
   exit(0)

# OK, didn't get enough info from file, try mimetype
# Use a format that gives both the mime type and
# the description at once, to save calls
oformat = r'--output-format=%m|%d'
mimewith = $(mimetype @(oformat) $ARG1)
[mimetypewith, descwith] = mimewith.strip().split('|')

# Usually we go with the extension
desc = descwith
# And we always do with text files, as mentioned above
trust = (trust or 'Unicode text' in filesez)
if not trust:
   mimewithout = $(mimetype -M @(oformat) $ARG1)
   [mimetypewithout, descwithout] = mimewithout.strip().split('|')
   if mimetypewith.split('/')[0] == mimetypewithout.split('/')[0]:
      # If the types are compatible, believe the extension
      desc = descwith
   else:
      desc = descwithout

# Calling everything a document is a waste of screenspace:
if desc.endswith(' document'):
   desc = desc[0:-9]

# All right, we've done the best we can:
print(desc)

如果您有更好的答案,请发布;我真的很想清理掉这个。

相关内容