【问题标题】:How to tell binary from text files in linux如何在linux中从文本文件中区分二进制文件
【发布时间】:2011-02-08 08:26:32
【问题描述】:

linux file 命令在识别文件类型方面做得非常好,并给出了非常细粒度的结果。 diff 工具能够区分二进制文件和文本文件,产生不同的输出。

有没有办法从文本文件中区分二进制文件?我想要的只是给定文件是否为二进制文件的是/否答案。因为很难定义二进制,假设我想知道diff 是否会尝试基于文本的比较。

为了澄清这个问题:我不在乎它是 ASCII 文本还是 XML,只要它是文本。另外,我不想区分 MP3 和 JPEG 文件,因为它们都是二进制文件。

【问题讨论】:

  • 如果您对diff 决定哪些文件是文本文件和哪些文件是二进制文件的方式感到满意,那么您可以随时查看diff 的源代码,看看他们是如何实现它的。

标签: linux binary diff ascii


【解决方案1】:

file 仍然是您想要的命令。任何文本文件(根据其启发式)都将在file 的输出中包含单词“text”;任何二进制文件都不会包含“文本”一词。

如果您不同意file 用于确定文本与非文本的启发式方法,则需要更好地指定问题,因为文本与非文本本质上是一个模糊的问题。例如,file 不会将 ASCII 中的 PGP 公钥块标识为“文本”,但您可以(因为它仅由可打印字符组成,即使它不是人类可读的)。

【讨论】:

  • file 的输出并不总是包含单词“text”,例如XML 文件并非如此。但是file -i 会给出 mime 类型,它确实包含单词“text”
  • 当我对 XML 文档执行 file 时,它会报告“XML 文档文本”。也许您正在测试的那个包含文件认为不是文本的编码二进制数据?
  • @gabor 我实际上得到了相反的效果。当我使用 -i 时,我得到了 xmls application/xml; charset=us-ascii 所以 grep -v text 不会过滤掉它。没有 -i 它工作正常
  • @Hilikus 你在什么系统上?来自 1:5.37-5ubuntu0.1 包的文件显示 text/xml
  • 我认为最可靠的选择是这样的:file -i <file> | grep -q -e text -e ascii。仅依赖 text 对于 JSON 也会失败。
【解决方案2】:

diff manual 指定

diff 判断文件是否为文本 或通过检查前几个二进制 文件中的字节;的确切数量 字节是系统相关的,但它是 通常几千。如果每个 文件那部分中的字节是 非空,diff 认为文件 成为文本;否则它认为 文件是二进制的。

【讨论】:

  • 这似乎是一个很好的启发式方法。 svn 与 Christoffer 下面提到的一样
【解决方案3】:

一种快速而简单的方法是在文件的前 K 或两个中查找 NUL 字符(零字节)。只要您不担心 UTF-16 或 UTF-32,任何文本文件都不应该包含 NUL

更新:根据 diff 手册,这正是 diff 的作用。

【讨论】:

  • (如果你没有在亚洲某个地方定居,)我会采用这种方法。
【解决方案4】:

你可以试一试

strings yourfile

命令并将结果的大小与文件大小进行比较...我不完全确定,但如果它们相同,则文件实际上是一个文本文件。

【讨论】:

  • “绝对”取决于strings 命令的实现。但是,是的,为这个想法 +1。
  • 我说“不完全确定”只是为了实现问题,但总的来说它应该可以工作。
  • +1,这适用于大多数 GNU 平台。 strings file | wc.c 然后wc -c file
  • 有什么方法可以在不创建临时文件的情况下做到这一点?此外,大文件可能会在这里造成问题
  • 字符串文件 | head -c | wc -c 并与 wc -c 文件比较
【解决方案5】:

此方法在确定文件是二进制文件还是文本文件时遵循grep 命令:

is_text_file() { grep -qIF '' "$1"; }

使用的 grep 选项:

  • -q安静;如果找到任何匹配项,立即以零状态退出
  • -I 处理二进制文件,就好像它不包含匹配数据一样
  • -F 将 PATTERNS 解释为固定字符串,而不是正则表达式。

使用的grep模式:

  • '' 空字符串。所有文件(空文件除外) 将匹配此模式。

注意事项

  • 根据此测试,空文件不被视为文本文件。 (GNU file 命令同意这个评估。)
  • 根据此测试,具有一个可打印字符的文件(例如 a)被视为文本文件。 (对我来说很有意义。)file 命令不同意这个评估。(使用 GNU 测试 file))
  • 这种方法只需要一个子进程来测试文件是文本文件还是二进制文件。

测试

# cd into a temp directory
cd "$(mktemp -d)"

# Create 3 corner-case test files
touch empty_file       # An empty file
echo -n a >one_byte_a  # A file containing just `a`
echo a >one_line_a     # A file containing just `a` and a newline

# Another test case: a 96KiB text file that ends with a NUL
head -c 98303 /usr/share/dict/words > file_with_a_null_96KiB
dd if=/dev/zero bs=1 count=1 >> file_with_a_null_96KiB

# Last test case: a 96KiB text file plus a NUL added at the end
head -c 98304 /usr/share/dict/words > file_with_a_null_96KiB_plus1
dd if=/dev/zero bs=1 count=1 >> file_with_a_null_96KiB_plus1

# Defer to grep to determine if a file is a text file
is_text_file() { grep -qI '^' "$1"; }

# Test harness
do_test() {
  printf '%22s ... ' "$1"
  if is_text_file "$1"; then
    echo "is a text file"
  else
    echo "is a binary file"
  fi
}

# Test each of our test cases
do_test empty_file
do_test one_byte_a
do_test one_line_a
do_test file_with_a_null_96KiB
do_test file_with_a_null_96KiB_plus1

输出

            empty_file ... is a binary file
            one_byte_a ... is a text file
            one_line_a ... is a text file
file_with_a_null_96KiB ... is a binary file
file_with_a_null_96KiB_plus1 ... is a text file

在我的机器上,似乎 grep 检查文件的前 96 KiB 以查找 NUL。 (使用 GNU grep 测试)。确切的交叉点取决于您机器的页面大小。

相关源码:https://git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c?h=v3.6#n1550

【讨论】:

    【解决方案6】:

    如今,“文本文件”一词含糊不清,因为文本文件可以用 ASCII、ISO-8859-*、UTF-8、UTF-16、UTF-32 等编码。

    请参阅here 了解 Subversion 是如何做到的。

    【讨论】:

    • 但今天的字面意思是 everything 使用字节 > 0x7F,甚至是翻译的手册页或 ISO-8859 文本文件。这将排除太多,即每个非 ASCII 文本文件。然而,由于在文本文件中看到 \0 的可能性几乎消失,RichieHindle 的方法似乎更适合我(即,对于自 80 年代初以来编写的每个文件)。
    【解决方案7】:

    在 ubuntu 中执行此操作的一种快速方法是在“列表”视图中使用 nautilus。类型列将显示它是文本还是二进制

    【讨论】:

      【解决方案8】:

      像 less、grep 这样的命令很容易(而且很快)检测到它。你可以看看他们的来源。

      【讨论】:

        猜你喜欢
        • 2016-12-14
        • 2016-01-20
        • 2011-04-26
        • 2019-02-22
        • 2011-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-16
        相关资源
        最近更新 更多