【问题标题】:How to check if the file is a binary file and read all the files which are not?如何检查文件是否为二进制文件并读取所有不是的文件?
【发布时间】:2013-05-21 13:18:56
【问题描述】:

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

例如编译的c文件。

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

【问题讨论】:

  • 最终所有文件都是二进制文件。文本文件恰好包含人类可读字符数据的二进制表示。没有任何一种区分文本和非文本的方法是 100% 可靠的。

标签: shell unix binaryfiles


【解决方案1】:

也许这就够了..

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

【讨论】:

    【解决方案2】:

    离开Bach's suggestion,我认为--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
    

    【讨论】:

    • 普通的 --mime 确实有效 (application/msword; charset=binary)。
    • @yugr 这很有趣 - 它几乎看起来像 file 中的一个错误,因为 .docx 文件为 --mime-encoding 打印 binary
    • 忘记在这里报告了,但是.doc bug was fixed
    【解决方案3】:

    grep

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

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

    注意:GNU grep 会将仅包含 NULL 字符的文件报告为文本,但它会在 BSD version 上正常工作。

    更多示例,请参见:How do I grep for all non-ASCII characters

    【讨论】:

      【解决方案4】:

      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                           |^@^@^@^@|
      

      另请参阅:How do I grep for all non-ASCII characters

      【讨论】:

      【解决方案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 字符,因此 check for other non-ASCII characters 可能会:

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

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

      【讨论】:

      • grep 是哪个版本的?使用 GNU grep 3.1,搜索 \x00 总是失败。
      • 我在 macOS 上使用 BSD grep,它似乎可以在它上面工作,而不是在 GNU 上。
      • @VladimirPanteleev 我有added more universal method,它适用于grep 版本,请检查。
      【解决方案6】:

      【讨论】:

        【解决方案7】:

        我用

        ! grep -qI . $path
        

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

        【讨论】:

        • 空文件情况可以通过添加|| ! test -s $path来控制。
        • Grep 用于空字符串 (''),而不是任何单个字符 ('.'):! fgrep -qI '' "$path"。这样,空文件和仅包含换行符(换行符)的文件将被视为文本。
        • @yugr,这并没有什么帮助,因为原始 Alois Mahdal 的代码不仅会将绝对空文件(零大小)视为二进制文件,还会将包含一个或多个换行符的文件视为二进制文件。但这很容易解决(见我上面的评论),Alois Mahdal 的想法很棒。
        【解决方案8】:

        试试下面的命令行:

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

        【讨论】:

        • 不错,但被 urt8 ascii 文件欺骗了。我用过:文件“$FILE”| grep -vq '文本'
        【解决方案9】:

        使用tr -d "[[:print:]\n\t]" &lt; 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
        ' _ '{}' + 
        

        【讨论】:

          【解决方案10】:
          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 退出。

          使用命令perldoc -f -X 阅读有关-B-T 检查的更多信息。

          【讨论】:

            【解决方案11】:

            使用 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
            

            【讨论】:

              【解决方案12】:

              改编自excluding binary file

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

              【讨论】:

              • 这应该是grep text;从历史上看,file 并不总是说 ASCII,而是例如“shell 脚本文本”。
              • @Jens 谢谢提醒。只需检查file 手册页,它应该是text
              • 谢谢,使用并调整它以查找文件夹中的所有二进制文件:find . -type f -exec file {} \; | grep -v text | cut -d: -f1
              • 如果文件名包含单词“text”怎么办?我现在使用 grep ".*:.*text"
              • @Algoman 我使用file -b,它不输出文件名。 (可能是 GNU 独有的功能)。
              【解决方案13】:

              使用实用程序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 manual page

              【讨论】:

              • 考虑使用'file --mine'。对于二进制文件,它报告“... charset=binary”,因此可以简单地使用 grep 查找正则表达式“binary$”。
              • @4dan - 也许是--mime? :)
              • @4dan 为我工作:file -bL --mime "$path" | grep -q '^text'。选项 -b 从输出中删除文件名,-L 取消引用符号链接。
              • 1.这适用于非 x86 架构吗? 2.你认为pdf文件二进制吗?
              • 答案应该包含 --mime 标志,否则对于所有可能的二进制格式匹配 file 的输出是不现实的(这样的正则表达式会太长且脆弱)。
              猜你喜欢
              • 2011-03-06
              • 2011-02-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-01-15
              • 1970-01-01
              相关资源
              最近更新 更多