Shell 如何检查文件是否为二进制文件并读取所有非二进制文件?

Shell 如何检查文件是否为二进制文件并读取所有非二进制文件?,shell,unix,binaryfiles,Shell,Unix,Binaryfiles,如何知道文件是否为二进制文件 例如,编译的c文件 我想从某个目录中读取所有文件,但我想忽略二进制文件。使用实用工具文件,示例用法: $ 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): M

如何知道文件是否为二进制文件

例如,编译的c文件


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

使用实用工具
文件
,示例用法:

 $ 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
改编自


使用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
可用于在“要测试的文件”为二进制时进行检查。上述命令将在二进制文件上以代码0退出,否则退出代码将为1

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

perl -E 'exit((-T $ARGV[0])?0:1);' file-to-test
同样,如果“要测试的文件”为文本(非二进制),则上述命令将以状态0退出


阅读更多关于
-B
-T
使用命令
perldoc-f-X

排除带有
tr-d“[[:print:]\n\T]”
的二进制文件是一种蛮力,但这也不是启发式猜测

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
' _ '{}' +

请尝试以下命令行:

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

<> P>唯一的缺点是,它会考虑一个空的文件二进制,但又一次,谁决定这是错误的?< /P> 下面是一个使用(在macOS/Unix上)检查单个文件的简单解决方案:

它基本上检查文件是否包含NUL字符

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

find . -type f -exec sh -c 'grep -q "\x00" {} || cat {}' ";"
或者更简单地使用grep

grep -rv "\x00" .
对于当前文件夹,请使用:

grep -v "\x00" *
不幸的是,上述示例不适用于,但是有一个解决方法

由于GNU
grep
忽略空字符,因此可能会喜欢:

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

我认为
--mime编码是从中获得可靠信息的最佳标志

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


警告:正如@yugr在下面的
中报告的那样。doc
文件报告了
应用程序/mswordbinary
的编码。在我看来,这就像一个bug——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

您也可以通过利用
diff
命令来实现这一点。检查以下答案:

cat
+
grep
假设binary表示包含空字符的文件,此shell命令可以帮助:

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

其中,
^@
字符表示空字符。因此,一旦找到这些控制字符,我们就假定文件是二进制的


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

$ 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                                       |^@^@|
$ printf "\x00\x00^@^@" | cat -v | hexdump -C
00000000  5e 40 5e 40 5e 40 5e 40                           |^@^@^@^@|
另请参见:.

grep
假设二进制表示包含不可打印字符(不包括空格、制表符或新行字符等空白字符)的文件,这可能会起作用(BSD和GNU):

注意:将报告仅包含空字符的文本文件,但它将在上正常工作


有关更多示例,请参见:。

也许这就足够了

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

这应该是
grep文本
;历史上,
文件
并不总是说ASCII,而是说“shell脚本文本”。@Jens谢谢提醒。只需检查
文件
手册页,它应该是
文本
。我刚刚意识到重新发明了轮子:在
中查找文件-类型f-exec文件{}\|grep text | perl-nle'split/:/;打印美元[0]”
;dogrep-i--color'string_to_search'$file;完成;谢谢,使用并调整它来查找文件夹中的所有二进制文件:
find-类型f-exec文件{}\|grep-v text | cut-d:-f1
如果文件名包含“text”一词会怎么样?我现在使用grep“*:.*text”所有文件最终都是二进制文件。文本文件恰好包含人类可读字符数据的二进制表示。没有区分文本和非文本的方法可以是100%可靠的。考虑使用“文件-MIX”。对于二进制文件,它报告“…charset=binary”,因此可以简单地grep regexp“binary$”@4dan-也许
--mime
?:)@4dan对我有用:
file-bL--mime“$path”| grep-q“^text”
。选项
-b
从输出中删除文件名,并且
-L
取消对符号链接的引用。1。这在非x86体系结构上有效吗?2.你认为PDF文件是二进制的吗?答案应该包含<代码> -MIME < /代码>标志,否则不符合实际情况,匹配所有可能的二进制格式的<代码>文件<代码>的输出(这样的正则表达式会太长和脆弱)。很好,但是被URT8 ASCII文件所欺骗。我使用了:file“$file”| grep-vq'text'那是什么版本的
grep
?使用GNU grep 3.1,搜索
\x00
总是失败。我在macOS上使用BSD grep,它似乎在它上工作,而不是在GNU上。@VladimirPanteleev我已经为
grep
两个版本都工作过了,请检查。这会产生一个错误的“二进制”结果,文本文件包含三个ASCII字符
\^
。添加了一个注释,还请检查:.Plain
--mime
确实有效(
应用程序/msword;charset=binary
)。@yugr这很有趣-它看起来几乎像
文件中的一个bug,因为
.docx
文件为
--mime编码打印
二进制文件。忘记在这里报告了,但是.空文件大小写可以通过添加
| |来控制!test-s$path
.Grep表示空字符串(
'
),不表示任何单个字符(
)。
):
!fgrep-qI“”“$path”
。这样,空文件和仅包含新行标记(换行符)的文件将被视为文本文件。@yugr,这并没有真正的帮助,
$ grep -P "[^\x00-\x7F]" file && echo Binary || echo Text
file --mime-encoding [FILES ...] | grep -v '\bbinary$'
$ 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
(cat -v file.bin | grep -q "\^@") && echo Binary || echo Text
grep -q "\^@" <(cat -v file.bin) && echo Binary
$ 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                                       |^@^@|
$ printf "\x00\x00^@^@" | cat -v | hexdump -C
00000000  5e 40 5e 40 5e 40 5e 40                           |^@^@^@^@|
$ grep '[^[:print:][:blank:]]' file && echo Binary || echo Text
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