ファイルがバイナリファイルかどうかを確認するにはどうすればよいですか?
たとえば、コンパイル済みのcファイル。
あるディレクトリからすべてのファイルを読みたいが、バイナリファイルを無視したい。
ユーティリティ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
私が使う
! grep -qI . $path
私が見ることができる唯一の欠点は、空のファイルバイナリを考慮することですが、それが間違っているかどうかを誰が決めるのでしょうか?
バイナリファイルを除く からの適応
find . -exec file {} \; | grep text | cut -d: -f1
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
チェックの詳細をご覧ください。
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
では機能しませんが、回避策があります。
grep
GNU grep
はNULL文字を無視しているため、 他の非ASCII文字をチェック のようにできます:
$ grep -P "[^\x00-\x7F]" file && echo Binary || echo Text
注:NULL文字のみを含むファイルでは機能しません。
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
次のコマンドラインを試してください:
file "$FILE" | grep -vq 'ASCII' && echo "$FILE is binary"
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する方法 。
バッハの提案 に進むと、--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
おそらくこれで十分でしょう。
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
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
' _ '{}' +
grep
バイナリが印刷できない文字(スペース、タブ、改行文字などの空白文字を除く)を含むファイルを意味すると仮定すると、これは動作する可能性があります(BSDとGNUの両方):
$ grep '[^[:print:][:blank:]]' file && echo Binary || echo Text
注: GNU grep
は、NULL文字のみを含むファイルをテキストとして報告しますが、 BSDバージョン では正常に機能します。
その他の例については、「 すべての非ASCII文字をgrepする方法 」を参照してください。
diff
コマンドを利用してこれを行うこともできます。この答えを確認してください: