如何检查文件是否是二进制文件?

问题描述 投票:0回答:13

如何知道一个文件是否是二进制文件?

例如,编译后的C文件是二进制文件。

我想读取某个目录中的所有文件,但我想忽略二进制文件。

shell unix binaryfiles
13个回答
79
投票

使用实用程序

file
,示例用法:

 $ file /bin/bash
 /bin/bash: Mach-O universal binary with 2 architectures
 /bin/bash (for architecture x86_64):   Mach-O 64-bit executable x86_64
 /bin/bash (for architecture i386): Mach-O executable i386

 $ file /etc/passwd
 /etc/passwd: ASCII English text

 $ file code.c
 code.c: ASCII c program text

file
手册页


16
投票

改编自排除二进制文件

find . -exec file {} \; | grep text | cut -d: -f1

15
投票

我用

! grep -qI . "$path"

我能看到的唯一缺点是它会考虑一个空文件二进制文件,但话又说回来,谁来决定这是否是错误的?

根据@mgutt的建议进行编辑:

在某些情况下,文件可能很大,因此根据您需要执行的操作,仅读取文件的一部分可能会更安全且足够:

head -c 1024 "$path" | grep -qI .

但请记住,您需要明智地选择尺寸; 1024 字节的文本加上一个空字节仍然是一个二进制文件。


5
投票

BSD
grep

这是一个使用 BSD

grep
(在 macOS/Unix 上)检查单个文件的简单解决方案:

grep -q "\x00" file && echo Binary || echo Text

主要检查文件是否包含 NUL 字符。

使用此方法,使用

find
实用程序递归读取所有非二进制文件,您可以执行以下操作:

find . -type f -exec sh -c 'grep -q "\x00" {} || cat {}' ";"

或者更简单地使用

grep
:

grep -rv "\x00" .

对于当前文件夹,请使用:

grep -v "\x00" *

不幸的是,上面的例子不适用于 GNU

grep
,但是有一个解决方法。

GNU
grep

由于 GNU

grep
忽略 NULL 字符,因此可以 检查其他非 ASCII 字符,例如:

$ grep -P "[^\x00-\x7F]" file && echo Binary || echo Text

注意:它不适用于仅包含 NULL 字符的文件。


4
投票
perl -E 'exit((-B $ARGV[0])?0:1);' file-to-test

可用于检查“要测试的文件”是否为二进制。上述命令将在二进制文件上以代码 0 退出,否则退出代码将为 1。

文本文件的反向检查可以类似于以下命令:

perl -E 'exit((-T $ARGV[0])?0:1);' file-to-test

同样,如果“要测试的文件”是文本(不是二进制),则上述命令将以状态 0 退出。

了解有关使用命令

-B
进行
-T
perldoc -f -X
检查的更多信息。


3
投票

使用 Perl 内置的

-T
文件测试操作符,最好在使用
-f
文件测试操作符确定它是一个普通文件之后:

$ perl -le 'for (@ARGV) { print if -f && -T }' \
    getwinsz.c a.out /etc/termcap /bin /bin/cat \
    /dev/tty /usr/share/zoneinfo/UTC /etc/motd
getwinsz.c
/etc/termcap
/etc/motd

这是该组的补充:

$ perl -le 'for (@ARGV) { print unless -f && -T }' \
    getwinsz.c a.out /etc/termcap /bin /bin/cat \
    /dev/tty /usr/share/zoneinfo/UTC /etc/motd
a.out
/bin
/bin/cat
/dev/tty
/usr/share/zoneinfo/UTC

3
投票

cat
+
grep

假设二进制表示包含 NULL 字符的文件,这个 shell 命令可以提供帮助:

(cat -v file.bin | grep -q "\^@") && echo Binary || echo Text

或:

grep -q "\^@" <(cat -v file.bin) && echo Binary

这是

grep -q "\x00"
的解决方法,适用于 BSD grep,但不适用于 GNU 版本。

基本上

-v
for
cat
会转换所有非打印字符,以便它们以控制字符的形式可见,例如:

$ printf "\x00\x00" | hexdump -C
00000000  00 00                                             |..|
$ printf "\x00\x00" | cat -v
^@^@
$ printf "\x00\x00" | cat -v | hexdump -C
00000000  5e 40 5e 40                                       |^@^@|

其中

^@
字符代表NULL字符。因此,一旦找到这些控制字符,我们就假设该文件是二进制文件。


上述方法的缺点是当字符不代表控制字符时可能会产生误报。例如:

$ printf "\x00\x00^@^@" | cat -v | hexdump -C
00000000  5e 40 5e 40 5e 40 5e 40                           |^@^@^@^@|

另请参阅:如何 grep 查找所有非 ASCII 字符


3
投票

放弃巴赫的建议,我认为

--mime-encoding
是从
file
获得可靠内容的最佳标志。

file --mime-encoding [FILES ...] | grep -v '\bbinary$'

将打印

file
认为具有非二进制编码的文件。如果您只需要文件名,您可以通过
cut -d: -f1
管道输出以修剪
:   encoding


警告:正如 @yugr 在下面报告的那样,

.doc
文件报告了
application/mswordbinary
的编码。在我看来,这就像一个错误 - mime 类型错误地与编码连接在一起。

$ for flag in --mime --mime-type --mime-encoding; do
    echo "$flag"
    file "$flag" /tmp/example.{doc{,x},png,txt}
  done
--mime
/tmp/example.doc:  application/msword; charset=binary
/tmp/example.docx: application/vnd.openxmlformats-officedocument.wordprocessingml.document; charset=binary
/tmp/example.png:  image/png; charset=binary
/tmp/example.txt:  text/plain; charset=us-ascii
--mime-type
/tmp/example.doc:  application/msword
/tmp/example.docx: application/vnd.openxmlformats-officedocument.wordprocessingml.document
/tmp/example.png:  image/png
/tmp/example.txt:  text/plain
--mime-encoding
/tmp/example.doc:  application/mswordbinary
/tmp/example.docx: binary
/tmp/example.png:  binary
/tmp/example.txt:  us-ascii

1
投票

尝试以下命令行:

file "$FILE" | grep -vq 'ASCII' && echo "$FILE is binary"

0
投票

tr -d "[[:print:]\n\t]" < file | wc -c
排除二进制文件是一种蛮力,但这也不是启发式猜测。

find . -type f -maxdepth 1 -exec /bin/sh -c '
   for file in "$@"; do
      if [ $(LC_ALL=C LANG=C tr -d "[[:print:]\n\t]" < "$file" | wc -c) -gt 0 ]; then
         echo "${file} is no ASCII text file (UNIX)"
      else
         echo "${file} is ASCII text file (UNIX)"
      fi
   done
' _ '{}' +

不过,以下使用

grep -a -m 1 $'[^[:print:]\t]' file
的强力方法似乎要快一些。

find . -type f -maxdepth 1 -exec /bin/sh -c '
   tab="$(printf "\t")"
   for file in "$@"; do
      if LC_ALL=C LANG=C grep -a -m 1 "[^[:print:]${tab}]" "$file" 1>/dev/null 2>&1; then
         echo "${file} is no ASCII text file (UNIX)"
      else
         echo "${file} is ASCII text file (UNIX)"
      fi
   done
' _ '{}' + 

0
投票

0
投票

grep

假设二进制意味着文件包含不可打印的字符(不包括空格、制表符或换行符等空白字符),这可能有效(BSD 和 GNU):

$ grep '[^[:print:][:blank:]]' file && echo Binary || echo Text

注意:GNU

grep
会将仅包含 NULL 字符的文件报告为文本,但它可以在 BSD 版本上正常工作。

有关更多示例,请参阅:如何 grep 查找所有非 ASCII 字符


0
投票

也许这就足够了..

if ! file /path/to/file | grep -iq ASCII ; then
    echo "Binary"
fi

if file /path/to/file | grep -iq ASCII ; then
    echo "Text file"
fi
© www.soinside.com 2019 - 2024. All rights reserved.