grep
やdiff
などの標準的なUnixユーティリティは、ヒューリスティックを使用してファイルを「テキスト」または「バイナリ」として分類します。 (たとえば、grep
の出力にはBinary file frobozz matches
のような行が含まれる場合があります。)
同様の「テキスト/バイナリ」分類を実行するためにzsh
スクリプトで適用できる便利なテストはありますか? (grep '' somefile | grep -q Binary
のようなもの以外。)
(私は、そのようなテストは必ずしもヒューリスティックであり、したがって不完全であることを理解しています。)
mime-typeだけをfile
に尋ねると、text/x-shellscript
やapplication/x-executable
など、さまざまなものが表示されますが、 「テキスト」の部分を確認すると、良い結果が得られるはずです。例(-b
は出力にファイル名がない場合):
file -b --mime-type filename | sed 's|/.*||'
別のアプローチは、isutf8
moreutils コレクションから。
ファイルが有効なUTF-8またはASCII、または短絡の場合は0で終了し、エラーメッセージが出力されます(-q
)、それ以外の場合は1で終了します。
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ファイルをリストします。
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
に対応する機能はありません。
参考文献:
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)を検出すると、バーフして終了します。
カテゴリは任意です。分類を行う方法に答える前に、(厳密な)定義が必要です。定義するためには、-目的が必要です。
では、その分類で何をしたいですか?
Perl -e'chomp(my$f=<>);print "binary$/" if -B $f;print "text$/" if -T _'
それを行います。 -B
および-T
のドキュメント を参照してください(そのページで文字列The -T and -B switches work as follows
を検索してください)。
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
私はこの答えは少し古いですが、私の友人はこれを行うための素晴らしい「ハック」を教えてくれたと思います。
diff
コマンドを使用して、ファイルをテストテキストファイルと照合します。
$ diff filetocheck testfile.txt
filetocheck
がバイナリファイルの場合、出力は次のようになります。
Binary files filetocheck and testfile.txt differ
このようにして、diff
コマンドを活用できます。スクリプトでチェックを行う関数を記述します。
私は https://github.com/audreyr/binaryornot に貢献しました==コマンドラインラッパーは(まだ)ありませんが、これはシンプルですPythonライブラリは十分簡単ですCLIからでも呼び出すことができます。かなり効率的なヒューリスティックを使用して、ファイルがテキストかバイナリかを判断します。