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


35

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

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

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


10
fileは、標準のユーティリティであり、ファイルマジックを実行して、ファイルの種類をその能力を最大限に引き出すことができます。ほとんどのテキスト形式を伝えることができ、バイナリ形式でかなりまともな仕事をします。ファイルがテキストであるかどうかを確認するだけなら、それがあなたの興味のあるコマンドです
。– Bratchley

@Bratchley:の一部のバージョンはfile、たとえばshell script、「テキスト」として分類したい一部のファイルに対して印刷されます。取得する方法があるfileだけで印刷するtextかはbinary
-kjo

1
@don_crisstiこの質問は、誰かに彼のbashスクリプトをデバッグさせようとしている人に関するものです。テキストを検出することは、スクリプトが行うべきことです。彼らはcutコマンドの1つに問題を抱えることになりました。
ブラッチリー

1
@don_crissti質問Bで機能する質問Aに答えがあるという事実は、必ずしもAをBの複製にするわけではありません。ファイルをテキストまたはバイナリとして分類する方法を探している人を考えてください。どちらがより便利です:そのスクリプトに固有の答えの中に一般的な答えが埋まっている「スクリプトをデバッグする」質問、または一般的な「フィールドをテキストまたはバイナリとして分類するにはどうすればよいですか?」
ジル 'SO-悪であるのをやめる'

1
@Gilles-読み方によって異なります。私は実際に質問をXY問題の典型的なケースとして見ています:OPはファイルがテキストファイルであるかどうかを確認したい-そしてfile出力をパイプすることcutが解決策だと考えています-確かに、失敗するスペースがあり、それが失敗しましたそこにいるほとんどの人はXではなくYに対応していますが、Stéphaneのコメントと回答は、ファイルがテキストかどうかを判断する適切な方法を示しています。
-don_crissti

回答:


27

mime-typefileのみを要求すると、などの多くの異なるものが得られますが、「テキスト」部分をチェックするだけで良い結果が得られるはずです。例(出力にファイル名がない場合):text/x-shellscriptapplication/x-executable-b

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

24
ちょうどあなたに応じて、覚えているfileあなたには、いくつかのテキスト形式を逃すかもしれない、: application/xml(やRSSなどの類似した)、 、、application/ecmascript 、...あなたはホワイトリストにそれらを持っていると思います。application/jsonimage/svg+xml
ボルデウィン

@Boldewynうわー、素敵な例!したがって、おそらくより良い答えは、印刷可能な文字のみを含む任意のファイルを受け入れることですが、何らかの方法でutf-8および同様のエンコードの問題にも対処することです。
-meuh

はい、それが以下の私の答えの要点です。唯一の問題は、その解決策はファイル全体を見る必要があるということです
...-Boldewyn

7
@Boldewyn原則として、application/*型は、開発とデバッグを容易にするためにテキストベースである場合でも、人間が消費することを意図していません。そのため、との両方がtext/xmlありますapplication/xml。したがって、それらをテキストとして考慮するかどうかの質問は、OPのニーズに依存します。
トビア

3
それともcut -d/ -f1
ステファンChazelas

20

別のアプローチはisutf8moreutilsコレクションから使用することです。

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


5
いい提案。argとしてディレクトリを指定すると、0が返されることに気づきました。少なくとも1が望ましいでしょう。しかし、その後、ゴミを入れ、ゴミを出します。
-meuh

13

GNU grepで使用されるヒューリスティックが好きな場合は、それを使用できます。

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

これは、NULが最初のバッファをファイルから読み込んでバイトを検索し(通常のファイルのためのいくつかのキロバイト、しかし、はるかに少ないパイプやソケットまたは一部のデバイス等の可能性/dev/random)。UTF-8ロケールでは、有効なUTF-8文字を形成しないバイトシーケンスにもフラグを立てます。LC_ALL言語が英語以外の場所に設定されていないことを前提としています。

この${1-$REPLY}フォームを使用すると、zshglob修飾子として使用できます。

ls -ld -- *(.+isbinary)

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


7

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)に遭遇すると、バーフして終了します。


4
GNU longオプションの代わりに-fand を使用-tすると、移植性が向上します。開くことができないファイルを「バイナリ」と呼ぶことに注意してください。空のファイルを「テキスト」と呼びます。
ステファンシャゼラス

同意した。知らない人のために、アドホックなドキュメントに長い形式を使用しましたiconv。しかし-f-t通常はより優れています。
ボルデウィン

7

を呼び出すスクリプトを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

文字列「テキスト」を異なるタイプの一部として使用するものもあります。たとえば、

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

同様にscript単語の一部である可能性がありますが、この場合は問題ありません。ただし、スクリプトは部分文字列ではなく単語"text"としてチェックする必要があります。

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

$ 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

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

の出力はfile、いずれかのシナリオで調整が必要であり、100%の信頼性はありません(Perlスクリプトのいくつかによって混同され、それらを「データ」と呼んでいます)。

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

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

参考文献:


残念ながらGNU fileのsvgファイルの出力:SVG Scalable Vector Graphics image単語textが含まれていません。このアプローチは、MIMEタイプをチェックするという受け入れられている答えよりも優れていると思いましたが、それでもいくつかのタイプが欠落しています。
ピーターコーデス

mimeタイプでは、まだ見逃しています。xtermののSVGファイルのために私が得ますimage/svg+xml。実際には-1000ファイルと同じものをチェックしただけで、MIMEタイプだけでは「テキスト」として6つしか出てきませんでした。少なくとも必要に応じて機能させることができるスクリプトを使用します。
トーマスディッキー

3

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

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

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

  • FTPでascii / binaryを選択する場合は、バイナリファイルをasciiとして転送しないでください(または破損します)。そのため、ファイルがプレーンテキスト、html、rtf、その他のファイルであるかどうかを確認します。しかし、疑わしいのは、バイナリを選択することです。また、ファイルに0x0A、0x0D、0x20-0x7Fなどのサブセットのみがあることをテストすることもできます。
  • 何らかのプロトコル(POP3、SMTP)でファイルを転送する場合は、base64でエンコードするか、単なるプレーンでエンコードするかをテストする必要があります。この場合、サポートされていない文字があるかどうかをテストする必要があります。
  • その他のケース...その他の定義がある場合があります。

3
perl -e'chomp(my$f=<>);print "binary$/" if -B $f;print "text$/" if -T _'

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


perl -le 'print -B $ARGV[0] ? "binary" : "text"' --より明確になるかもしれません。またはperl -le 'print -B $_ ? "binary" : "text", @ARGV > 1 ? "\t$_" : "" for @ARGV' --
jrw32982はモニカをサポートしています


1

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

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

$ diff filetocheck testfile.txt

あれば今すぐfiletocheckバイナリファイルで、出力は次のようになります。

Binary files filetocheck and testfile.txt differ

この方法では、diffコマンドを活用して、たとえばスクリプトでチェックを行う関数を作成できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.