web-dev-qa-db-ja.com

ファイルを「バイナリ」または「テキスト」として分類する便利な方法はありますか?

grepdiffなどの標準的なUnixユーティリティは、ヒューリスティックを使用してファイルを「テキスト」または「バイナリ」として分類します。 (たとえば、grepの出力にはBinary file frobozz matchesのような行が含まれる場合があります。)

同様の「テキスト/バイナリ」分類を実行するためにzshスクリプトで適用できる便利なテストはありますか? (grep '' somefile | grep -q Binaryのようなもの以外。)

(私は、そのようなテストは必ずしもヒューリスティックであり、したがって不完全であることを理解しています。)

35
kjo

mime-typeだけをfileに尋ねると、text/x-shellscriptapplication/x-executableなど、さまざまなものが表示されますが、 「テキスト」の部分を確認すると、良い結果が得られるはずです。例(-bは出力にファイル名がない場合):

file -b --mime-type filename | sed 's|/.*||'
27
meuh

別のアプローチは、isutf8moreutils コレクションから。

ファイルが有効なUTF-8またはASCII、または短絡の場合は0で終了し、エラーメッセージが出力されます(-q)、それ以外の場合は1で終了します。

20
Wander Nauta

GNU grepが使用するヒューリスティックが気に入った場合は、次のように使用できます。

isbinary() {
  LC_MESSAGES=C grep -Hm1 '^' < "${1-$REPLY}" | grep -q '^Binary'
}

それは ファイルから読み取られた最初のバッファーでNULバイトを検索します (通常のファイルでは数キロバイトですが、パイプやソケット、または/dev/random)。 UTF-8ロケールでは、有効なUTF-8文字を形成しないバイトシーケンスにもフラグを立てます。 LC_ALLは、言語が英語ではないものに設定されていません。

${1-$REPLY}形式では、これをzshグロブ修飾子として使用できます。

ls -ld -- *(.+isbinary)

binaryファイルをリストします。

13

fileを呼び出すスクリプトを作成し、ケースステートメントを使用して、関心のあるケースを確認できます。

例えば

#!/bin/sh
case $(file "$1") in
(*script*|*\ text|*\ text\ *)
    echo text
    ;;
(*)
    echo binary
    ;;
esac

もちろん、興味深い多くの特別なケースがあるかもしれません。 stringsのコピーでlibmagicを確認するだけで、約200件のケースが表示されます。たとえば、

Konqueror cookie text
Korn Shell script text executable
LaTeX 2e document text
LaTeX document text
Linux Software Map entry text
Linux Software Map entry text (new format)
Linux kernel symbol map text
LISP/Scheme program text
Lua script text executable
LyX document text
M3U playlist text
M4 macro processor script text

文字列「text」を別のタイプの一部として使用するものもあります。たとえば、

SoftQuad troff Context intermediate   
SoftQuad troff Context intermediate for AT&T 495 laser printer
SoftQuad troff Context intermediate for HP LaserJet

同様に、scriptはWordの一部である可能性がありますが、この場合は問題ありません。しかし、スクリプトは"text"Wordとして、substringではなく。

注意として、fileの出力では、常に「スクリプト」または「テキスト」を持つ正確な説明は使用されません。特別なケースは考慮すべきものです。フォローアップは、--mime-typeは機能しますが、このアプローチは機能しません.svgファイル。ただし、テストでは、svg-filesに対して次の結果が表示されます。

$ ls -l *.svg
-r--r--r-- 1 tom users  6679 Jul 26  2012 pumpkin_48x48.svg
-r--r--r-- 1 tom users 17372 Jul 30  2012 sink_48x48.svg
-r--r--r-- 1 tom users  5929 Jul 25  2012 vile_48x48.svg
-r--r--r-- 1 tom users  3553 Jul 28  2012 vile-mini.svg
$ file *.svg
pumpkin_48x48.svg: SVG Scalable Vector Graphics image
sink_48x48.svg:    SVG Scalable Vector Graphics image
vile-mini.svg:     SVG Scalable Vector Graphics image
vile_48x48.svg:    SVG Scalable Vector Graphics image
$ file --mime-type *.svg
pumpkin_48x48.svg: image/svg+xml
sink_48x48.svg:    image/svg+xml
vile-mini.svg:     image/svg+xml
vile_48x48.svg:    image/svg+xml

1000のファイルがmimeタイプの出力で「テキスト」を含む6のみを表示した後に選択したものです。おそらく、mime-type出力の最後にある「xml」を一致させることは、「SVG」を一致させるよりも、たとえば、スクリプトを使用してdoここでの提案に戻ります。

fileの出力はどちらのシナリオでもある程度の調整が必要であり、100%の信頼性はありません(「データ」と呼ぶ私のPerlスクリプトのいくつかで混乱しています)。

fileの実装は複数あります。最も一般的に使用されるものは libmagic で機能します。これは、さまざまなプログラムから使用できます(おそらくzshから直接ではありませんが、 python できます)。

シェル、Perl、Ruby、Pythonのファイルテスト比較表 によると、Perlには-Tこの情報を提供するために使用できるオプション。ただし、zshに対応する機能はありません。

参考文献:

7
Thomas Dickey

iconvがファイルを読み取れるかどうかを確認してみてください。これはfile(最初から数バイトを読み取るだけ)よりもパフォーマンスは劣りますが、より信頼性の高い結果が得られます。

ENCODING=utf-8
if iconv --from-code="$ENCODING" --to-code="$ENCODING" your_file.ext > /dev/null 2>&1; then
    echo text
else
    echo binary
fi

これによりiconvは基本的に何もしなくなりますが、無効なデータ(この例では無効なUTF-8)を検出すると、バーフして終了します。

7
Boldewyn

カテゴリは任意です。分類を行う方法に答える前に、(厳密な)定義が必要です。定義するためには、-目的が必要です

では、その分類で何をしたいですか?

  • FTPでascii/binaryを選択する場合は、バイナリファイルをasciiとして転送しないことが重要です(転送しないと破損します)。したがって、ファイルがプレーンテキスト、html、rtf、その他のファイルであるかどうかをテストする必要があります。しかし、疑わしい場合は、バイナリを選択してください。また、ファイルに0x0A、0x0D、0x20-0x7Fのようなサブセットのみがあることもテストする必要があるかもしれません。
  • 何らかのプロトコル(POP3、SMTP)でファイルを転送したい場合は、base64でエンコードするか、単純にエンコードするかを選択してテストする必要があります。この場合、サポートされていない文字があるかどうかをテストする必要があります。
  • その他の場合は…その他の定義がある場合があります。
3
ESL
Perl -e'chomp(my$f=<>);print "binary$/" if -B $f;print "text$/" if -T _'

それを行います。 -Bおよび-Tのドキュメント を参照してください(そのページで文字列The -T and -B switches work as followsを検索してください)。

3
msh210

fileには、ファイルのエンコーディングの検出を試みるオプション--mime-encodingがあります。

 $file --mime-encoding Documents/poster2.pdf 
Documents/poster2.pdf: binary
 $file --mime-encoding projects/linux/history-torvalds/Makefile 
projects/linux/history-torvalds/Makefile: us-ascii
 $file --mime-encoding graphe.tex 
Dgraphe.tex: us-ascii
 $file --mime-encoding software.tex 
software.tex: utf-8

file --mime-encoding | grep binaryを使用して、ファイルがバイナリファイルかどうかを検出できます。長いテキストファイル内の1つの無効な文字によって混乱する可能性がありますが、確実に機能します。

たとえば、次のシェルスクリプトにcatのエイリアスを設定して、誤ってバイナリファイルを開いて端末が破壊されるのを防ぎます。

#! /bin/sh -

[ ! -t 1 ] && exec /bin/cat "$@"
for i
do
    if file --mime-encoding -- "$i" | grep -q binary
    then
        hexdump -C -- "$i"
    else
        /bin/cat -- "$i"
    fi
done
3
lgeorget

私はこの答えは少し古いですが、私の友人はこれを行うための素晴らしい「ハック」を教えてくれたと思います。

diffコマンドを使用して、ファイルをテストテキストファイルと照合します。

$ diff filetocheck testfile.txt

filetocheckがバイナリファイルの場合、出力は次のようになります。

Binary files filetocheck and testfile.txt differ

このようにして、diffコマンドを活用できます。スクリプトでチェックを行う関数を記述します。

1
user3019105

私は https://github.com/audreyr/binaryornot に貢献しました==コマンドラインラッパーは(まだ)ありませんが、これはシンプルですPythonライブラリは十分簡単ですCLIからでも呼び出すことができます。かなり効率的なヒューリスティックを使用して、ファイルがテキストかバイナリかを判断します。

1