web-dev-qa-db-ja.com

ファイルがバイナリファイルであるかどうかを確認し、そうでないすべてのファイルを読み取る方法は?

ファイルがバイナリファイルかどうかを確認するにはどうすればよいですか?

たとえば、コンパイル済みのcファイル。

あるディレクトリからすべてのファイルを読みたいが、バイナリファイルを無視したい。

41
Refael

ユーティリティ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マニュアルページ

47
Adam Siemion

私が使う

! grep -qI . $path

私が見ることができる唯一の欠点は、空のファイルバイナリを考慮することですが、それが間違っているかどうかを誰が決めるのでしょうか?

10
Alois Mahdal

バイナリファイルを除く からの適応

find . -exec file {} \; | grep text | cut -d: -f1
9
gongzhitaao
Perl -E 'exit((-B $ARGV[0])?0:1);' file-to-test

「テストするファイル」がバイナリであるときはいつでもチェックするために使用できます。上記のコマンドは、バイナリファイルのコード0で終了します。それ以外の場合、終了コードは1になります。

テキストファイルの逆チェックは、次のコマンドのようになります。

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

同様に、「file-to-test」がテキスト(バイナリではない)の場合、上記のコマンドはステータス0で終了します。

コマンド-Bを使用した-Tおよびperldoc -f -Xチェックの詳細をご覧ください。

4
Onlyjob

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文字のみを含むファイルでは機能しません。

3
kenorb

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
tchrist

次のコマンドラインを試してください:

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

cat + grep

バイナリがNULL文字を含むファイルを意味すると仮定すると、このシェルコマンドは以下を支援できます。

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

参照: すべての非ASCII文字をgrepする方法

1
kenorb

バッハの提案 に進むと、--mime-encodingfile から信頼できるものを得るための最良のフラグだと思います。

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
dimo414

おそらくこれで十分でしょう。

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
0
Mike Q

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
vron

grep

バイナリが印刷できない文字(スペース、タブ、改行文字などの空白文字を除く)を含むファイルを意味すると仮定すると、これは動作する可能性があります(BSDとGNUの両方):

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

注: GNU grep は、NULL文字のみを含むファイルをテキストとして報告しますが、 BSDバージョン では正常に機能します。

その他の例については、「 すべての非ASCII文字をgrepする方法 」を参照してください。

0
kenorb

diffコマンドを利用してこれを行うこともできます。この答えを確認してください:

https://unix.stackexchange.com/questions/275516/is-there-a-convenient-way-to-classify-files-as-binary-or-text#answer-40287

0
tonix