何千ものファイルがあるフォルダ内のファイルタイプを判別する方法を探しています。ファイル名はあまりわかりませんし、拡張子もありませんが、種類は異なります。具体的には、ファイルがsqliteデータベースであるかどうかを判断しようとしています。
file
コマンドを使用すると、1秒あたり2〜3個のファイルのタイプが判別されます。これは、遅すぎることを除けば、問題に対処するための良い方法のようです。
次に、sqlite3で各ファイルを開いて、エラーが発生するかどうかを確認してみました。そうすれば、1秒あたり4〜5個のファイルをチェックできます。はるかに良いですが、これを行うためのより良い方法があるかもしれないと思います。
file
でテストされた1秒あたり2〜3ファイルは、私には非常に遅いようです。 file
は実際に、さまざまなテストを実行して、ファイルタイプを判別します。特定の種類のファイル(sqlite)を探していて、他のすべてのファイルを特定する必要がないため、既知のsqliteファイルを試して、どのテストが実際に特定するかを判断できます。次に、-e
フラグを使用して他のユーザーを除外し、完全なファイルセットに対して実行できます。 manページ を参照してください:
-e, --exclude testname
Exclude the test named in testname from the list of tests made to
determine the file type. Valid test names are:
apptype
EMX application type (only on EMX).
text
Various types of text files (this test will try to guess the
text encoding, irrespective of the setting of the ‘encoding’
option).
encoding
Different text encodings for soft magic tests.
tokens
Looks for known tokens inside text files.
cdf
Prints details of Compound Document Files.
compress
Checks for, and looks inside, compressed files.
elf
Prints ELF file details.
soft
Consults magic files.
tar
Examines tar files.
編集:私は自分でいくつかのテストを試しました。概要:
file
を約15%高速化できます。これは何かですが、私が期待した大きな改善ではありません。file
を実行しているのか、それとも...?16MBのsqlite DBファイルの場合、次のようにしました。
#!/bin/bash
for i in {1..1000}
do
file sqllite_file.db | tail > out
done
コマンドラインでのタイミング:
~/tmp$ time ./test_file_times.sh; cat out
real 0m2.424s
user 0m0.040s
sys 0m0.288s
sqllite_file.db: SQLite 3.x database
別のテストを試して除外すると、決定が単一のテストに基づいて行われると想定して、ファイルを識別するのは「ソフト」(つまり、マジックファイルルックアップ)テストです。したがって、他のすべてのテストを除外するようにfile
コマンドを変更しました。
file -e apptype -e ascii -e encoding -e tokens -e cdf -e compress -e elf -e tar sqllite_file.db | tail > out
これを1000回実行する:
~/tmp$ time ./test_file_times.sh; cat out
real 0m2.119s
user 0m0.060s
sys 0m0.280s
sqllite_file.db: SQLite 3.x database
http://www.sqlite.org/fileformat.html を見ると、SQLiteフォーマットは文字列 "SQLite format 3\000"で始まります。ファイルのhead -c 16
をチェックしてフォーマットをチェックできるように思えます。これは、より汎用的なツールを使用するよりも高速であると思います。
file
のsqliteファイルの魔法の説明を見ると、どちらかのSQLite format 3
または** This file contains an SQLite
ファイルの先頭。
したがって、これらのチェックだけでマジックファイルを作成する(そして@ire_and_cursesソリューションのように組み込みテストを無効にする)か、手動でチェックを行うことができます。
case $(head -c 31 < "$file") in
("** This file contains an SQLite"*) echo sqlite 2;;
("SQLite format 3"*) echo sqlite 3;;
esac
ファイルごとにhead
を実行するため、あまり効率的ではありません。少しの努力で、Perlでそれを実行して、1回のPerl呼び出しで複数のファイルの最初の31バイトを読み取ることができます。