有没有一种方便的方法将文件分类为“二进制”或“文本”?

kjo*_*kjo 44 files text

标准 Unix 实用程序喜欢grepdiff使用一些启发式将文件分类为“文本”或“二进制”。(例如grep的输出可能包括像Binary file frobozz matches.)

是否可以在zsh脚本中应用方便的测试来执行类似的“文本/二进制”分类?(除了类似的东西grep '' somefile | grep -q Binary。)

(我意识到任何这样的测试都必然是启发式的,因此是不完美的。)

meu*_*euh 33

如果你问file的只是MIME类型,你会得到很多不同的像text/x-shellscript,以及application/x-executable等,但我想,如果你只是检查“文本”部分,你应该得到很好的效果。例如(-b输出中没有文件名):

file -b --mime-type filename | sed 's|/.*||'
Run Code Online (Sandbox Code Playgroud)

  • 请记住,根据你的 `file`,你可能会错过一些文本格式:`application/xml`(和类似的 RSS)、`application/ecmascript`、`application/json`、`image/svg+xml`、 ...你必须将这些列入白名单。 (26认同)
  • @Boldewyn 原则上,`application/*` 类型不适合人类使用,即使它们可能是基于文本的以促进开发和调试。这就是为什么同时存在“text/xml”和“application/xml”的原因。因此,是否将它们视为文本的问题取决于 OP 的需求。 (7认同)
  • 或者`cut -d/ -f1` (3认同)

Wan*_*uta 26

另一种方法是isutf8moreutils集合中使用。

如果文件是有效的 UTF-8 或 ASCII 或短路,则以 0 退出,打印错误消息(用 静音-q),否则以 1 退出。

  • 不错的建议。我只是注意到将目录作为 arg 使其返回 0。我至少更喜欢 1。但是,垃圾进,垃圾出。 (5认同)

Sté*_*las 17

如果您喜欢 GNU 使用的启发式方法grep,则可以使用它:

isbinary() {
  LC_MESSAGES=C grep -Hm1 '^' < "${1-$REPLY}" | grep -q '^Binary'
}
Run Code Online (Sandbox Code Playgroud)

在从文件中读取的第一个缓冲区中搜索 NUL 字节(对于常规文件为几千字节,但对于管道或套接字或某些设备(如/dev/random)可能要少得多)。在 UTF-8 语言环境中,它还标记不构成有效 UTF-8 字符的字节序列。它假定LC_ALL没有设置为语言不是英语的东西。

${1-$REPLY}表单允许您将其用作zshglob 限定符:

ls -ld -- *(.+isbinary)
Run Code Online (Sandbox Code Playgroud)

将列出二进制文件。


Bol*_*wyn 9

您可以尝试确定是否iconv可以读取文件。这比file(它从一开始只读取几个字节)性能差,但会给你更可靠的结果:

ENCODING=utf-8
if iconv --from-code="$ENCODING" --to-code="$ENCODING" your_file.ext > /dev/null 2>&1; then
    echo text
else
    echo binary
fi
Run Code Online (Sandbox Code Playgroud)

iconv基本上是一个无操作,但如果它遇到无效数据(在这个例子中是无效的 UTF-8),它会 barf 并退出。

  • 使用 `-f` 和 `-t` 代替 GNU 长选项会使其更易于移植。请注意,它会将无法打开的文件称为“二进制”。它会将空文件称为“文本”。 (4认同)

Tho*_*key 8

您可以编写一个调用 的脚本file,并使用 case 语句来检查您感兴趣的案例。

例如

#!/bin/sh
case $(file "$1") in
(*script*|*\ text|*\ text\ *)
    echo text
    ;;
(*)
    echo binary
    ;;
esac
Run Code Online (Sandbox Code Playgroud)

当然,可能有许多特殊情况值得关注。只是检查strings的副本libmagic,我看到大约 200 个案例,例如,

Konqueror cookie text
Korn shell script text executable
LaTeX 2e document text
LaTeX document text
Linux Software Map entry text
Linux Software Map entry text (new format)
Linux kernel symbol map text
Lisp/Scheme program text
Lua script text executable
LyX document text
M3U playlist text
M4 macro processor script text
Run Code Online (Sandbox Code Playgroud)

有些使用字符串“text”作为不同类型的一部分,例如,

SoftQuad troff Context intermediate   
SoftQuad troff Context intermediate for AT&T 495 laser printer
SoftQuad troff Context intermediate for HP LaserJet
Run Code Online (Sandbox Code Playgroud)

同样script可以是一个词的一部分,但我认为在这种情况下没有问题。但是脚本应该检查"text"作为一个,而不是一个子字符串

提醒一下,file输出不使用总是有“脚本”或“文本”的精确描述。特殊情况需要考虑。后续评论说--mime-type,对于.svg文件,这种方法行不通。但是,在测试中,我看到 svg 文件的这些结果:

$ ls -l *.svg
-r--r--r-- 1 tom users  6679 Jul 26  2012 pumpkin_48x48.svg
-r--r--r-- 1 tom users 17372 Jul 30  2012 sink_48x48.svg
-r--r--r-- 1 tom users  5929 Jul 25  2012 vile_48x48.svg
-r--r--r-- 1 tom users  3553 Jul 28  2012 vile-mini.svg
$ file *.svg
pumpkin_48x48.svg: SVG Scalable Vector Graphics image
sink_48x48.svg:    SVG Scalable Vector Graphics image
vile-mini.svg:     SVG Scalable Vector Graphics image
vile_48x48.svg:    SVG Scalable Vector Graphics image
$ file --mime-type *.svg
pumpkin_48x48.svg: image/svg+xml
sink_48x48.svg:    image/svg+xml
vile-mini.svg:     image/svg+xml
vile_48x48.svg:    image/svg+xml
Run Code Online (Sandbox Code Playgroud)

我在看到一千个文件后选择了它,在 mime 类型的输出中只显示了 6 个带有“文本”的文件。可以说,在 mime 类型输出的末尾匹配“xml”可能比匹配“SVG”更有用,但是使用脚本来做这会让你回到这里提出的建议。

的输出file在任何一种情况下都需要一些调整,并且不是 100% 可靠的(它被我的几个 Perl 脚本混淆,称它们为“数据”)。

的实现不止一种file。最常用的一个在 中工作libmagic,它可以在不同的程序中使用(也许不能直接从 中使用zsh,但python可以)。

根据shell、Perl、Ruby 和 Python 的文件测试比较表,Perl 有一个-T选项可用于提供此信息。但它没有列出zsh.

进一步阅读:


lge*_*get 7

file有一个--mime-encoding尝试检测文件编码的选项。

\n\n
\xc2\xa0$file --mime-encoding Documents/poster2.pdf \nDocuments/poster2.pdf: binary\n\xc2\xa0$file --mime-encoding projects/linux/history-torvalds/Makefile \nprojects/linux/history-torvalds/Makefile: us-ascii\n\xc2\xa0$file --mime-encoding graphe.tex \nDgraphe.tex: us-ascii\n\xc2\xa0$file --mime-encoding software.tex \nsoftware.tex: utf-8\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以使用它file --mime-encoding | grep binary来检测文件是否是二进制文件。它工作可靠,尽管它可能会被长文本文件中的单个无效字符混淆。

\n\n

例如,我cat为以下 shell 脚本添加别名,以避免无意中打开二进制文件而破坏我的终端:

\n\n
#! /bin/sh -\n\n[ ! -t 1 ] && exec /bin/cat "$@"\nfor i\ndo\n    if file --mime-encoding -- "$i" | grep -q binary\n    then\n        hexdump -C -- "$i"\n    else\n        /bin/cat -- "$i"\n    fi\ndone\n
Run Code Online (Sandbox Code Playgroud)\n