如何在目录中查找二进制文件?

40

我需要在一个目录中找到二进制文件。我希望使用file命令来实现,并且之后将使用grep命令检查结果。但问题是我不知道什么是二进制文件。对于二进制文件,file命令会给出什么信息,或者我应该使用grep检查什么?


你在这里提到的“二进制”文件是什么类型的? 你系统上是否有适当的“二进制”文件? file 命令对它有何描述? - Etan Reisner
我不知道什么样的二进制文件,因为我的作业没有定义它,只是让我编写一个使用grep命令(和其他命令)来查找目录中的二进制文件并写出它们的权限的shell脚本。所以我对二进制文件类型一无所知。 - Kiss-Budai Matyas
这对我来说似乎过于模糊了,我会要求澄清。尽管考虑到使用“grep”的建议,我猜它的意思是“包含空字节”。 - Etan Reisner
所有文件都是二进制的。 "二进制"意味着您不知道文件的实际格式或在上下文中它不重要。一些文件是文本文件。文本文件是指整个文件可以使用特定字符编码解码为文本字符串的文件。所有文件都可以使用几种不同的字符编码进行解码。只有在您知道文件是文本并使用编写它的字符编码时,才能这样做。 - Tom Blodget
1
可执行文件特别是:https://unix.stackexchange.com/questions/1484/how-to-find-all-binary-executables-recursively-within-a-directory - Ciro Santilli OurBigBook.com
10个回答

40

这将查找所有非文本、二进制和空文件。

编辑

仅使用grep的解决方案(来自Mehrdad的评论):

最初的回答:

grep -rIL .

最初的回答

这不需要任何其他工具,只需要使用findgrep

find . -type f -exec grep -IL . "{}" \;

-I参数告诉grep将二进制文件视为不匹配

-L参数仅打印未匹配的文件

.匹配任何其他内容


编辑2

这将查找所有非空二进制文件:

find . -type f ! -size 0 -exec grep -IL . "{}" \;

2
这在OSX上不起作用,因为它将HTML文件输出为二进制文件。 - Chris F
3
我认为你可以简化成 grep -r -I -L . - user541686
看起来你是对的。然而,我很久以前就看过这个问题了,所以我不记得为什么要在那里加入find。没有额外的分支,这也会快得多! - t.animal
我刚刚运行了这个程序,它找到了所有的“非二进制”文件。 - Chris F
也许你认为是“非二进制”的文件实际上是空的?它们也会显示出来(我猜是因为它们不是文本)。 - t.animal
显示剩余6条评论

18

只需要提到Perl-T测试文本文件,以及它的相反-B测试二进制文件。

$ find . -type f | perl -lne 'print if -B'

如果要打印任何二进制文件,请使用-T进行相反操作:文本文件。

它不是完全可靠的,因为它只查看前1,000个字符左右,但比建议在这里使用的一些临时方法好。详见man perlfunc。以下是摘要:

"-T"和"-B"开关的工作原理如下。首先检查文件的第一个块或其他内容,以查看它是否包含非ASCII字符的有效UTF-8。如果是,则是"-T"文件。否则,该文件的相同部分将被检查是否有奇怪的字符,例如奇怪的控制代码或具有高位设置的字符。如果超过三分之一的字符都很奇怪,则是"-B"文件;否则它是"-T"文件。同时,任何包含在检查部分中的零字节的文件都被认为是二进制文件。


4
在这个现代化的时代(毕竟2020年已经是21世纪的第三个十年),我认为正确的问题应该是“如何找到所有非utf-8的文件”?Utf-8相当于文本文件的现代版本。
使用utf-8编码文本的非ascii代码点将引入非ascii字节(即,最高有效位设置为1的字节)。然而,并不是所有这样的字节序列都形成有效的utf-8序列。
你需要使用来自moreutils软件包的isutf8。
$ isutf8 -l /bin/*
/bin/[
/bin/acyclic
/bin/addr2line
/bin/animate
/bin/applydeltarpm
/bin/apropos
⋮

快速检查:

$ file $(isutf8 -l /bin/*)
/bin/[:             ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4d70c2142fc672d8a69d033ecb6693ec15b1e6fb, for GNU/Linux 3.2.0, stripped
/bin/acyclic:       ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d428ea52eb0e8aaf7faf30914710d8fbabe6ca28, for GNU/Linux 3.2.0, stripped
/bin/addr2line:     ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=797f42bc4f8fb754a49b816b82d6b40804626567, for GNU/Linux 3.2.0, stripped
/bin/animate:       ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=36ab46e69c1bfea433382ffc9bbd9708365dac2b, for GNU/Linux 3.2.0, stripped
/bin/applydeltarpm: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a1fddcbeec9266e698782596f2dfd1b4f3e0b974, for GNU/Linux 3.2.0, stripped
/bin/apropos:       symbolic link to whatis
⋮

你可能希望反转测试并获取所有文本文件。 使用-i

$ isutf8 -il /bin/*
/bin/alias
/bin/bashbug
/bin/bashbug-64
/bin/bg
⋮
$ file -L $(isutf8 -il /bin/*)
/bin/alias:      a /usr/bin/sh script, ASCII text executable
/bin/bashbug:    a /usr/bin/sh - script, ASCII text executable, with very long lines
/bin/bashbug-64: a /usr/bin/sh - script, ASCII text executable, with very long lines
/bin/bg:         a /usr/bin/sh script, ASCII text executable
⋮

是的,它会读取整个文件,但速度相当快,如果你想要准确性的话...


我希望它能以某种方式告诉我第一个非UTF-8字节的索引! - undefined
1
@Ciro Santilli OurBigBook.com 我的 _isutf8_(版本1.2)显示 /bin/tr: line 1, char 41, byte 40: Expecting bytes in the following ranges: 00..7F C2..F4 Fedora, bleeding edge? Nah - undefined
哦,你说得对。我开得太快了,只检查了“-l”。太棒了! - undefined

2
作为一项任务,如果我给你完整的解决方案,你可能会讨厌我;-)所以这里有一个小提示:
如果您搜索类似于.的正则表达式,则grep命令将默认输出二进制文件列表,该正则表达式将匹配任何非空文件:
grep . *

输出:

[...]
Binary file c matches
Binary file e matches

你可以使用 awk 来仅获取文件名,使用 ls 打印权限。请参阅各自的手册页 (man grep, man awk, man ls)。

0

我的第一个回答与这里使用的find命令基本相同。我认为你的教练想让你了解使用file命令来理解magic numbers概念,该命令将其分解为多种类型。

对于我的目的,只需要这么简单:

最初的回答

file * | grep executable

但是有很多种方法可以做到这一点。原始回答翻译成"最初的回答"。

1
如果您的文件名包含破折号,使用 file ./* | grep executable 更安全。 - schmijos

0

使用findgrep的答案是可行的,但它非常慢,因为它为每个文件创建一个新进程。以下解决方案更有效:

comm -2 -3 <(find . -type f -not -empty | sort) <(grep -rIl . . | sort)

0

来自遥远未来的晚回答。这里的首要问题是问题没有明确定义。术语“二进制文件”含糊不清,并且提问者似乎对此感到困惑。

什么是“二进制文件”?

我将同意Wikipedia上的观点:

二进制文件是一种不是文本文件的计算机文件[1]。“二进制文件”通常被用作指代“非文本文件”的术语。

如果不是二进制文件,那么什么是文本文件呢?要识别文本文件,就需要事先知道其编码,否则该文件看起来就像一个未知的二进制文件。

我用来回答“这是什么类型的文件?”问题的工具是file实用程序。该实用程序足够聪明,可以尝试使用不同的编码读取文件以查看是否有意义:

如果一个文件在魔术文件中找不到匹配项,则会检查该文件是否似乎是文本文件。 ASCII、ISO-8859-x、非ISO 8位扩展ASCII字符集(例如Macintosh和IBM PC系统上使用的字符集)、UTF-8编码的Unicode、UTF-16编码的Unicode以及EBCDIC字符集可以通过构成每个字符集可打印文本的字节的不同范围和序列进行区分。
如果一个文件不是"文本"类型,则根据维基百科的定义,它必须是"二进制"类型。
然而,file工具可以检测到两种类型的二进制文件:
- 可执行文件:主要是Linux systemd中的ELF文件,但还有其他众所周知的二进制类型。 - 数据文件:其他所有类型的文件。
递归地列出目录中的"二进制"文件。
以下内容考虑了许多边缘情况,如文件名:
  • 名字中包含"ELF"或"data"
  • 名字中有空格(尽管换行符会使其断开)
  • 名字中有一个冒号:
shopt -s globstar
file -0 **/* | sed -nE 's/\x0:\s*(ELF|data).*//p'

注意事项

我假设我们主要搜索 ELF 文件作为我们的可执行文件和库格式。还有其他竞争格式,如 COFF 和 PE,所以这些不会被检测到。


-1

我认为确定文件性质的最佳工具是文件实用程序。 在我的一个目录中,唯一被Nautilus文件管理器标识为二进制的文件。 对于这个文件,只有命令ls | xargs file返回“数据”,没有任何其他信息。


管道 ls 总是一个坏主意。可以用命令 file * 或者递归搜索的方式 shopt -s globstar; file **/* 替代这个命令。 - SenhorLucas

-2

Linux中的二进制文件格式为ELF

当您在二进制文件上运行file命令时,输出包含单词ELF。您可以使用grep进行搜索。

在命令行上:

file <binary_file_name>

因此,如果您想在目录中查找二进制文件(例如在Linux中),可以执行以下操作:

ls | xargs file | grep ELF


1
请参考上面此答案中的评论 - 并非所有二进制文件都是可执行文件;你的回答是错误的。 - tink
1
我认为这是一个有用的答案 - 这是“二进制文件”的一个有效解释。但是我建议只做 file ./*。通过 xargs 管道 ls 是不必要的复杂和脆弱的。 - mwfearnley

-4

你可以使用find和参数-executable,这基本上就是你想要的。

man手册说:

   -executable
          Matches files which are executable and directories which are searchable (in a file name resolution sense).  This takes into  account  access control lists and other permissions artefacts which the -perm test ignores.  This test makes use of the access(2) system call, and so can be fooled by NFS servers which do UID mapping (or root-squashing), since many systems implement access(2) in the client's kernel and so  cannot make  use  of  the  UID mapping information held on the server.  Because this test is based only on the result of the access(2) system call, there is no guarantee that a file for which this test succeeds can actually be executed.

这是您想要的结果:

# find /bin  -executable -type f | grep 'dmesg'
/bin/dmesg

1
但是例如,这将在图片、音乐文件或其他文件上给我一个错误提示,那么在这种情况下,什么是二进制文件的确切含义呢? - Kiss-Budai Matyas
所以,你想要所有不是纯文本的文件,对吗?你可以这样做: #for i in *; do file $i | grep -v ASCII | awk -F:'{print $1}'; done - Breno Leitão
9
“find”的“-executable”选项涉及权限,而不是文件内容。原帖明确提到了“二进制”文件,而不是“可执行”文件。 - Michael Jaros
尽管答案不正确,但由于在包含大量文件的文件夹中查找的强大功能,我仍然发现它非常有用,可以为您提供良好的第一次过滤。 - Germán Bouzas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接