linux中如何区分二进制文件和文本文件

linux中如何区分二进制文件和文本文件,linux,binary,diff,ascii,Linux,Binary,Diff,Ascii,linuxfile命令在识别文件类型方面做得非常好,并给出了非常细粒度的结果。diff工具能够区分二进制文件和文本文件,产生不同的输出 有没有办法区分二进制文件和文本文件?我想要的只是一个是/否的答案,不管给定的文件是二进制文件。因为很难定义二进制,我想知道diff是否会尝试基于文本的比较 为了澄清这个问题:我不在乎它是ASCII文本还是XML,只要它是文本就行。另外,我不想区分MP3和JPEG文件,因为它们都是二进制文件。一种快速而肮脏的方法是在文件的前一两个K中查找NUL字符(零字节)。只要

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

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


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

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

更新:根据diff手册,这正是diff所做的。

现在术语“文本文件”是不明确的,因为文本文件可以用ASCII、ISO-8859-*、UTF-8、UTF-16、UTF-32等编码


请参阅Subversion是如何做到这一点的。

您可以尝试给出

strings yourfile

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

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

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

指定

diff确定文件是否为文本 或者通过检查前几个 文件中的字节数;确切人数 字节依赖于系统,但它是 通常是几千人。如果每 文件中该部分的字节是 非null,diff将文件视为 是文本;否则,它认为 文件必须是二进制的


less、grep等命令很容易(快速)检测到它。您可以查看它们的源代码。

在ubuntu中实现这一点的快速方法是在“列表”视图中使用nautilus。“类型”列将向您显示其文本还是二进制文件。在确定文件是二进制文件还是文本时,此方法遵循
grep
命令:

is_text_file() { grep -qIF '' "$1"; }
使用的grep选项:
  • -q
    安静;如果发现任何匹配项,立即退出,状态为零
  • -I
    处理二进制文件,就像它不包含匹配数据一样
  • -F
    将模式解释为固定字符串,而不是正则表达式
使用的grep模式:
  • ''
    空字符串。所有文件(空文件除外) 将匹配此模式
笔记
  • 根据此测试,空文件不被视为文本文件。(GNU
    file
    命令与此评估一致。)
  • 根据此测试,具有一个可打印字符的文件(例如
    A
    )被视为文本文件。(对我来说很有意义。)(
    文件
    命令与此评估不一致。(使用GNU
    文件
    测试)
  • 这种方法只需要一个子进程来测试文件是文本还是二进制文件
试验
#将cd放入临时目录
cd“$(mktemp-d)”
#创建3个角落案例测试文件
触摸空文件#空文件
echo-na>one_byte_a#仅包含'a'的文件`
echo a>one_line_a#一个只包含'a'和换行符的文件
#另一个测试用例:以NUL结尾的96KiB文本文件
head-c 98303/usr/share/dict/words>file_与_a_null_96KiB
dd if=/dev/zero bs=1 count=1>>带有空值的文件
#最后一个测试用例:一个96KiB的文本文件加上在末尾添加的NUL
head-c 98304/usr/share/dict/words>file_,带_a_null_96KiB_plus1
dd if=/dev/zero bs=1 count=1>>带有空值的文件
#根据grep确定文件是否为文本文件
是文本文件({grep-qI'^''$1”;}
#测试线束
do_test(){
打印文件“%22s…”“$1”
如果是文本文件“$1”;则
echo“是一个文本文件”
其他的
echo“是一个二进制文件”
fi
}
#测试我们的每个测试用例
是否测试空\u文件
是否测试一个字节
测试一条线吗
测试文件是否为空
是否使用空值加1的测试文件
输出 在我的机器上,grep似乎在检查一个文件的前96kib是否有
NUL
。(使用GNU
grep
进行测试)。确切的交叉点取决于机器的页面大小


相关源代码:

(如果你没有在亚洲的某个地方定居,我会采用这种方法。但实际上,现在所有东西都使用bytes>0x7F,甚至翻译的手册页或ISO-8859文本文件。这将排除太多的内容,即每个非ASCII文本文件。然而,由于在文本文件中看到\0的可能性几乎消失,RichieHindle的方法似乎更适合我(也就是说,对于自80年代初以来编写的每个文件而言)。其中“肯定”取决于
strings
命令的实现。但是,是的,这个想法是+1。我说的“不完全确定”只是为了实现问题,但总的来说它应该是可行的。+1,这在大多数GNU平台上都是可行的
strings文件| wc.c
然后
wc-c文件
。有没有不创建临时文件的方法?此外,大型文件可能会在字符串文件| head-c | wc-c和wc-c文件之间产生问题,如果您对
diff
决定哪些文件是文本文件,哪些文件是二进制文件的方式感到满意,那么您可以始终只查看
diff
的源代码,并查看它们是如何实现的
            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