version 1.1
目次
Frui/篩(以下Fruiと表記)は、UNIXコマンドの"find"と"grep"を組み合わせたような処理をします。検索結果を「篩い落としていく」様子からこう名付けました。
検索機能は、本家findに似せた動作を基本にしていますが、操作が直感的であること、入力が楽であることを優先しています。 grep機能は本家grepほど機能は豊富ではありませんが、出力結果はほぼ同じになるようにしています。
主にfind,grepと異なる点は以下の通りです。
JRE(Java実行環境)1.4以上がインストールされている必要があります。(1.3で使いたい方は、Java1.3で使用する場合を参照してください。)
アーカイブを適当なディレクトリに展開します。ここでは"/opt/frui"とします。
エイリアスを使う場合は、以下のコマンドを実行します。
alias frui="java -jar /opt/frui/frui.jar"
エイリアスを使わない場合は、以下のスクリプトを記述したファイルを"frui"という名前でパスの通っているディレクトリに保存し、実行権限を与えてください。
#!/bin/sh java -jar /opt/frui/frui.jar $*
コマンドを実行してみましょう。"frui -v"でバージョン情報が表示されたらインストール完了です。
アーカイブを適当なディレクトリに展開します。ここでは"C:\Program Files\Frui"とします。
次に、以下のコマンドを記述したファイルを"frui.bat"という名前でパスの通っているディレクトリに保存してください。("% *"はXP、2000、NTでしか使えないので注意。)
@echo off java -jar "C:\Program Files\Frui\frui.jar" %*
コマンドを実行してみましょう。"frui -v"でバージョン情報が表示されたらインストール完了です。
基本的には、インストールで設定したものを削除すればアンインストールとなります。
オプションによって(特に移動条件)は、ディレクトリや一時ファイルが作成されますので、不要な場合は削除してください。
実際に検索してみましょう。ここではUNIX系OSでの簡単な例を示します。まずは、検索ルートとするディレクトリに"cd"で移動します。そのディレクトリ配下は次のようになっているとしましょう。
Main.java (350bytes) src/A.java (870bytes) src/A.txt ( 12bytes)
拡張子がjavaでサイズが500バイト以上のファイルを検索する場合は、次のようにします。
$ frui --find .java --size +500 --path ./src/A.java $
"--find"や"--size"などはオプションで、検索条件などの指定を行います。オプションを複数指定した場合は、AND条件で評価されます。上記の場合では、"--size"の評価は"src/A.txt"に対しては行いません。"--path"は出力形式オプションで、パスだけを表示します。
オプションには短縮表記があり、例えば"--find"は"-f"と、"--size"は"-s"と指定することもできます。前に実行したコマンドは短縮表記にすると以下のようになります。
$ frui .java -s +500 -p
オプションは、最低1つは指定しなければなりません。(動作設定を除く。詳しくは、オプションを参照。)特に条件を指定したくない場合は、"path"オプションなどの出力形式を指定して下さい。
また、オプションには次のような特殊ルールがあります。
ファイル情報とは、ファイルパスと一致行の情報をまとめた物で、grepなどで一致行の情報がある場合はgrepの出力結果のようになります。
オプションには、0〜2個のパラメータを指定します。オプションによってパラメータの数は異なりますが、1つのオプションでパラメータが変わることはありません。例えば、copyオプションはパラメータを2個取りますが、
$ frui --copy A --find
のように指定すると、"--find"はオプションではなく、copyオプションの第2パラメータと解釈されてしまいます。
パラメータの種類のうち、「文字列パターン」は共通の指定方法があります。
文字列パターンが指定できるオプションの短縮表記に"i"を付加すると、パターンマッチの際に大文字小文字の区別をせずに処理されます。
"-fi list" = "-f list" + ignore-case "-gi /NEW/" = "-g /NEW/i" = "-gi /NEW/i"
各オプションの詳細です。ここでは説明していませんが、オプションを大まかに分類すると、検索条件、移動条件、出力形式、動作設定、情報、その他、があります。これらはマニュアルには記載していませんが、helpオプションで出力されるヘルプに書かれています。
検索を行う場合は、検索条件、移動条件、出力形式のいずれかを、最低1つは指定しなければなりません。特に指定する条件がない場合は、出力形式を明示的に指定すれば検索できます。
オプションの分類ごとにいくつかの異なるルールがあります。
見出しの次の行に書かれているのは、"短縮表記、完全表記、パラメータ"の説明です。短縮表記は入力しやすさを、完全表記は覚えやすさを、それぞれ優先した表記になっています。
-a --and パラメータ:なし
このオプション以降のオプションをAND条件で結合します。デフォルトはAND条件なので、OR条件をAND条件に戻すときに指定します。
-B --binary パラメータなし
ファイルがバイナリファイルかどうかを調べます。このオプションは処理に時間がかかる可能性があります。詳細はパフォーマンスについてを参照してください。
-c --copy パラメータ:1.文字列パターン 2.置き換え文字列 (要modifyプロパティ)
パス文字列が文字列パターンに一致した場合、置き換え文字列で置き換えたパス文字列のパスにファイルをコピーします。コピー先のディレクトリが存在しない場合は作成されます。最終更新日時もコピーします。最終更新日時以外の属性はコピーされません。(実装詳細:Java1.4ではファイルの属性はほとんど操作できません。)
$ frui .txt ./test.txt ./test/a.txt $ frui -c test text ./text.txt ./text/a.txt $ frui .txt ./test.txt ./text.txt ./test/a.txt ./text/a.txt $
-C --clear パラメータ:なし
grep系オプションは、結果に行情報を付加して次のオプションに渡しますが、その行情報をクリアしたい場合に使用します。
NOT条件と併せて使用することもできますが、実用的ではありません。このオプションで処理される時点で行情報があるものが"真"となるため、grep系(行情報を取得する検索条件)条件のAND条件の後で使用すると必ず一致しないことになります。OR条件でgrep系と非grep系と組み合わせた場合には一致しますが、いずれにしてもgrep系の処理で一致した分は除外されるため、意味のない処理となります。
-d --directory パラメータ:1.ディレクトリ
検索を開始するディレクトリを指定します。findコマンドの第1パラメータに指定するものと同じです。指定しない場合は、カレントディレクトリとなります。
複数指定した場合、指定した順に検索を実行します。例えば、ディレクトリを2つ指定した場合、1番目のディレクトリの検索が終了した後、2番目のディレクトリの検索が実行されます。
次の例は、ルートディレクトリ以下の"hosts"を含むパスを検索します。(検索に時間がかかりますので試す場合は注意してください。)
$ find / -regex ".*hosts.*" /etc/hosts $ frui -d / hosts /etc/hosts $
(短縮なし) --depth パラメータ:1.深度の指定
検索するディレクトリの深度を指定します。深度は、検索開始ディレクトリが1、そのサブディレクトリが2、となります。
深度の指定は、"1..2"(1から2まで),"1.."(1からすべて),"..2"(2まですべて),"2"(同左)の4種類があります。
stdinオプションを指定している場合は無効となります。
-e --evaluate パラメータ:可変
任意のクラスを条件に指定します。特殊な検索条件を加えたい場合などに使用します。詳しくは、evaluateの使い方を参照してください。
-f --find パラメータ:1.文字列パターン
パス文字列が指定した文字列パターンに一致しているかどうかを調べます。使い方でも説明したように、オプションを省略した場合はこのオプションとみなされます。また、このオプションのみ「拡張子パターン」が利用可能です。
次の例は、"2006"をディレクトリ名かファイル名に含む画像ファイルを検索します。
$ find . -iname "*.jpg" -or -iname "*.gif" -or -iname "*.png" -or -iname "*.bmp" | grep 2006 ./photo/kyoto.20060403.jpg ./watch2006/a.gif ./watch2006/b.gif $ frui .jpg,gif,png,bmp 2006 ./photo/kyoto.20060403.jpg ./watch2006/a.gif ./watch2006/b.gif $
(短縮なし) --fullpath パラメータ:なし
検索ルートの指定が絶対パスか相対パスかに関わらず、常にフルパス(絶対パス)で出力します。
-g --grep パラメータ:1.文字列パターン
ファイルの内容が指定した文字列パターンに一致しているかどうかを調べます。いわゆる"GREP"です。
次の例は、CヘッダファイルでstdioヘッダをincludeしているファイルをGREP検索します。
$ frui .h -g "#include" -g stdio ./usr/include/bzlib.h:118:#include./usr/include/mntent.h:39:#include ./usr/include/stdio.h:71:#include $ frui .h -g "/#include.+stdio/" ./usr/include/bzlib.h:118:#include ./usr/include/mntent.h:39:#include ./usr/include/stdio.h:71:#include $
-h --help パラメータ:なし
簡易ヘルプを出力します。
(短縮なし) --html パラメータ:なし
結果をHTML形式で出力します。HTMLには検索結果へのリンクが記述されます。
-i --stdin パラメータ:なし
検索開始ディレクトリから取得せず、ファイル情報を標準入力から取り込みます。Fruiでは処理できない検索や、ファイルに出力した結果を再度検索したりする場合に使用します。標準入力については、使用するシェルの使い方を知っておく必要があります。
入力されたパスが存在しない場合、そのパスはスキップされます。このとき、スキップされたパスが1以上存在した場合は、verboseオプションを指定すればスキップした件数が結果件数と共に出力されます。
例えば、UNIXのfindの-newerオプションで絞り込んだあとでFruiを使いたい場合は次のようにします。
$ find . -newer timestamp.file | frui -i .java,jsp,html
また、ファイルから取り込む場合は次のようにします。
$ frui -i .java,jsp,html < result.file
-l --list パラメータ:なし
UNIXのls(-l)コマンド、MS-DOSのdirコマンドのように、ファイルのサイズや更新日時の一覧を出力します。ただし、システムに依存する情報は出力できません。
ls -lコマンドで表示させたい場合は、次のようにします。(1MB以上のアーカイブファイルを検索する。)
$ frui .lzh,zip,z,gz,bzip2 -s +1M | xargs ls -l
-m --move パラメータ:1.文字列パターン 2.置き換え文字列 (要modifyプロパティ)
パス文字列が文字列パターンに一致した場合、置き換え文字列で置き換えたパス文字列のパスにファイルを移動します。移動先のディレクトリが存在しない場合は作成されます
$ frui .txt ./test.txt ./test/a.txt $ frui -m test text ./text.txt ./text/a.txt $ frui .txt ./test/a.txt ./text/a.txt $
! --not パラメータ:なし
次に指定した検索条件オプションの条件を反転します(NOT条件)。
-n --name パラメータ:1.文字列パターン
ファイル名が指定した文字列パターンに一致しているかどうかを調べます。
$ frui --find aaa ./aaa.txt ./aaa/1.txt $ frui -n aaa ./aaa.txt $
-N --number パラメータ:なし
ファイルの行数を出力します。但し、行情報を取得済みの場合、一致行数を出力します。
$ frui -n a.txt -N 5 ./a.txt $ frui -n a.txt -g te ./a.txt:1:test ./a.txt:2:tear ./a.txt:3:text ./a.txt:4:teach ./a.txt:5:tempo $ frui -n a.txt -g /te.t/ ./a.txt:1:test ./a.txt:3:text $ frui -n a.txt -g /te.t/ -N 2 ./a.txt $
-o --or パラメータ:なし
このオプション以降のオプションをOR条件で結合します。二項演算ではなく、AND条件が指定されるまでの全てのオプションをOR結合します。結合されたオプションは短絡評価されます。OR条件をAND条件をはさまずに2回以上指定した場合、指定ごとに条件がグループになります。
$ frui -o A B -a C -o D E -o F G --verbose [MODE] directory=[] verbose=true depthRange= [PROPS] [FILTER] ( Find(A) or Find(B) ) & Find(C) & ( Find(D) or Find(E) ) & ( Find(F) or Find(G) ) & PrintInfo # (以下省略)
OR結合はファイル単位で短絡評価を行うため、grep系条件は最初の条件に一致した時点で評価が終了してしまい、最初の条件に一致した行しか検出できません。行に対してOR条件を適用するには、正規表現でOR条件を指定するか、grepを拡張したオプションを定義するなどの対応が必要となります。
-p --path パラメータ:なし
行情報が取得済みの場合でも、パスのみを出力します。
$ frui -n a.txt -g /te.t/ ./a.txt:1:test ./a.txt:3:text $ frui -n a.txt -g /te.t/ -p ./a.txt $
-q --quiet パラメータ:なし
結果を出力しません。移動処理などのあとで結果を表示させたくない場合などに使用します。
-r --replace パラメータ:1.文字列パターン 2.置き換え文字列 (要modifyプロパティ, replaceプロパティ)
重要なファイルを破壊してしまう恐れがあります。ご使用の際は、十分にご注意ください。
GREP処理を行い、一致した文字列を指定した文字列に置き換え、ファイル内容を更新します。zipオプションと同時には指定できません。
置き換えの際、元のファイルの改行コードを維持するようになっています。
置き換えを実行した場合、一時ディレクトリ(実装詳細:Javaシステムプロパティ"java.io.tmpdir"のパス+"Frui")に強制的にバックアップを作成します。
-s --size パラメータ:1.ファイルサイズ条件
ファイルのサイズを調べます。(実装詳細:java.io.File#length()の値を使用します。)
条件は、比較条件+サイズ値で指定します。
比較指定は、次の3つの記号のいずれか1つを指定できます。省略時は=と判断されます。(findのsizeオプションは、+は指定サイズ超、-は指定サイズ未満となっています。)
サイズ値は、数値+単位が指定できます。単位は、TGMK(TB,GB,MB,KB)のいずれか1文字が大文字小文字に関係なく指定できます。基数は1024で、単位が指定された場合はバイト数を算出します。そのため、単位を指定したときは小数も指定できます。単位を指定しない場合は整数のみ指定できます。
(短縮なし) --suffix パラメータ:なし
拡張子のセット、つまりユニークな一覧を出力します。
拡張子は、初めて出現した時に出力されます。出力される順序は、この順序になります。
ファイル名の最後に出現する"."(ピリオド)以降を拡張子とみなして出力します。"."が登場しない場合は拡張子なしとみなされ、"."を出力します。ディレクトリは対象外です。
-t --time パラメータ:1.日時条件
ファイルの最終更新日時を調べます。(実装詳細:java.io.File#lastModified()の値を使用します。)
条件は、範囲指定+日付値で指定します。日付値は、絶対値と相対値での指定ができます。
範囲指定は、次の5つの記号のいずれか1つを指定できます。省略時は=と判断されます。
絶対値指定の場合、年月日(yyyyMMdd)、年月日時(yyyyMMddHH)、年月日時分(yyyyMMddHHmm)、年月日時分秒(yyyyMMddHHmmss)が指定できます。このとき、最も下位の単位が指定単位となります。
相対値指定の場合、整数値+単位が指定でき、整数値を単位分遡った日時の指定となります。単位は、DHMS(日・時・分・秒)のいずれか1文字が大文字小文字に関係なく指定できます。
指定方法は複雑ですが、最終的には2つの時間点の間かどうかで判断されます。次の説明を読んでみてください。
現在日時を2006/03/27としたとき "=20060325"または"=2d"を指定した場合 開始時点 = 2006/03/25の00:00:00 終了時点 = 翌日2006/03/26の00:00:00より過去で最も近い時間 2006/03/25 2006/03/26 00:00:00 00:00:00 ------+--------------------------+--------------- [ ] ここから ここまで "[20060325"または"[2d"を指定した場合 開始時点 = 2006/03/25の00:00:00 終了時点 = ∞ 2006/03/25 2006/03/26 00:00:00 00:00:00 ------+--------------------------+--------------- [ ここから 終了時点なし "-20060325"または"-2d"を指定した場合 開始時点 = 2006/03/26の00:00:00 終了時点 = ∞ 2006/03/25 2006/03/26 00:00:00 00:00:00 ------+--------------------------+--------------- [ ここから 終了時点なし
また、verboseオプションを付けると詳細が表示されますので、参考にしてください。
$ frui --verbose -t -20060201 -t ]20060327 [MODE] directory=. verbose=true depthRange= [PROPS] [FILTER] Time(2006/02/02_00:00:00:000-) & Time(-2006/03/27_23:59:59:999)
-T --text パラメータ:なし
ファイルがテキストファイルかどうかを調べます。("--not --binary" と同義)このオプションは処理に時間がかかる可能性があります。詳細はパフォーマンスについてを参照してください。
-u --upper パラメータ:1.上限数
一致した件数が指定した上限数に達した時点で検索を打ち切ります。
-v --version パラメータ:なし
バージョンを表示します。
-V --VERSION パラメータ:なし
バージョンの詳細情報を表示します。
(短縮なし) --verbose パラメータ:なし
検索開始前に、オプションとプロパティを出力します。
検索終了後に、実行時間と結果件数を出力します。
-w --waste パラメータ:なし
該当ファイルをFrui専用の「くずかご」に「捨て」(移動させ)ます。専用の「くずかご」については、wasteプロパティを参照してください。
「くずかご」の下に日付(yyyyMMdd)のディレクトリを作成し、さらにその下に時刻(HHmmss)のディレクトリを作成します。ファイルは、その下をルートとした相対パスに移動されます。
-x --examine パラメータ:1.ファイル種類
ファイルの種類を調べます。種類は、次の5つのいずれか1つを大文字小文字に関係なく指定できます。
-z --zip パラメータ:1.ZIPファイル内のファイル名パターン
ZIPフォーマットファイル内のエントリを行に見立ててGREPを実行します。replaceオプションと同時には指定できません。
いくつかの機能では、オプションではなく設定を必要とするものがあります。また、動作の詳細を設定できる機能もあります。これらは、プロパティに設定します。通常は、システムプロパティ(Javaの-Dオプション)に指定します。
"設定値"は、設定する値についての説明です。設定値のカッコ内の値は既定値です。カッコがないものは既定値がありません。(実装詳細:ブール値はBoolean.getBoolean()で取得します。)
設定値:true/false(false)
エラーが発生した場合に、エラーの詳細を出力するようにします。(実装詳細:スタックトレースなどを出力します。)
設定値:true/false(false)
ファイル内検索などを行う際に、バイナリファイルを除外するために検出を行うかどうかを指定します。指定した場合、バイナリファイルの検出を行い、バイナリファイルの場合は検索対象から除外します(NOT条件も無効)。
設定値:true/false(false)
ファイル内検索などを行う際に、エンコーディングタイプの自動検出を行うかどうかを指定します。システムの既定エンコーディングではないファイルを扱う場合に使用します。ファイル内容の変更を行う処理の場合は、このオプションを指定しないとエンコーディングの整合性が崩れてしまいます。
設定値:完全修飾クラス名
文字エンコーディングタイプ自動検出を行うクラスを指定します。指定するクラスは、net.argius.frui.io.EncodingTypeのサブクラスである必要があります。
設定値:数値フォーマット書式
ファイルサイズ出力時のフォーマットを指定します。指定しない場合、フォーマットせずに出力します。(実装詳細:指定した場合、 java.text.DecimalFormatを使用します。)
設定値:日時フォーマット(yyyy/MM/dd HH:mm:ss)
日時出力時のフォーマットを指定します。(実装詳細:java.text.SimpleDateFormatを使用します。)
設定値:パターン文字列のスペース区切りリスト
常に検索対象から外すパターンを指定します。パターンはfindオプションと同じものが指定できます。複数指定する場合は、二重引用符("")で囲みます。
設定値:true/false(false)
注意:この設定を有効にすると、大事なファイルを破壊してしまったり、削除してしまったりする可能性があります
ファイルを変更する処理を許可するかどうかを指定します。許可しない場合、常に読み取り専用で処理を行い、ファイルの移動や内容の変更はエラーとなります。
設定値:true/false(false)
検索結果に出力されるパスの先頭に付いている、カレントディレクトリの部分を取り除いて出力するかどうかを指定します。結果の出力幅を節約したい場合などに使用します。
トリムは出力時のみ行われ、パターンマッチではトリムされていない状態のパスで処理されます。
設定値:パスセパレータ文字列
システムのパスセパレータと異なる文字で結果を出力したい場合に指定します。
置き換えは出力時のみ行われ、パターンマッチでは置き換え前の状態のパスで処理されます。
注意:この設定を有効にすると、大事なファイルを破壊してしまったり、削除してしまったりする可能性があります
設定値:true/false(false)
Replaceオプションの使用を許可するかどうかを指定します。特に、Replaceは強力な処理のため、modifyプロパティと二重にガードするようにしています。
設定値:ディレクトリのパス
wasteオプションで使用するディレクトリを指定します。指定しない場合、wasteオプションが使用できません。
Fruiの設計から見たパフォーマンスについての説明です。ここでは、実装の詳細も交えて説明しています。
Fruiは、詳細のパフォーマンスよりも、ユーザインタフェースやプログラムの構造を単純にすることを優先しています。ユーザインタフェースを向上させることで、実行開始までの速度が改善できると考えたからです。入力に15秒かかって処理が10秒で終わる処理と、入力に5秒かかって処理が20秒で終わる処理では、後者のほうが人間の労力を減らすことができます。
起動時の処理に関しては、極力処理速度が上がるようにしています。例えばオプションの組み立てはインラインで行う、インスタンス生成の遅延、などです(但し、これによって確実にパフォーマンスが改善されているかどうかは実証していません)。Javaはプロセス起動の遅さ(特に初回)は致命的ですが、ハードウェアの性能が高ければ、それなりの速度が出るようになってきました。
当初、処理を単純にするために、パターンを全て正規表現で処理するようにしていました。
しかしながら、正規表現が不要な場合のエスケープを考慮すると、却って複雑になってしまうため、正規表現の場合と同じインタフェースを持つパターンマッチ処理を実装して置き換えました。
バイナリファイルの検出は、ファイルを最初から上限サイズ(約64KB)までを読み込み、通常の文字として表示可能でないデータが見つかった時点でバイナリファイルと判断し、処理を打ち切ります。テキストファイルの検出はこの逆を行うので、必ず上限サイズまで読み込んでしまうことになります。(但し、文字エンコーディングタイプが特定されている場合はその時点でテキストファイルと判断します。)他の条件で十分に絞り込んだあとで指定することをおすすめします。
検索条件は指定された順に評価されるため、処理が速くかつ大きく絞り込める条件を先に指定すれば、処理効率が上がります。
効率の観点から分類すると、処理の速い順に、ファイルパス文字列パターン条件、ファイル属性条件、ファイル内容条件となります。ファイル内容条件は1ファイルにつき何回も条件判定を行いますので、必然的に重い処理となります。また、タイムスタンプやサイズなどのファイル属性を調べる処理は、ファイルパスを文字列として条件判定するより時間のかかる処理です。
次のような指定順序は非常に効率の悪い検索となってしまいます。
$ frui -T -s +25K .java # すべてのファイルにテキストファイル判定!
この場合は、前述した処理の速い順に条件を並び替えると処理効率が格段に向上します。また、冗長な条件と思われる場合でも、対象のファイル名に含まれる文字が1文字でも特定されていれば最初に指定すれば、大幅な枝刈りが期待できます。
$ frui F .java -s +25K -T # パスに"F"を含んでいるものだけが2番目以降の条件に挑戦できる
Fruiは、コマンドとしてだけでなく、APIとしてもある程度利用できるようになっています。 例えば、次のようにすればカレントディレクトリ以下のすべてのJavaソースファイルが取得できます。
File[] files = FruiRunner.getFiles(new Operation[]{new Find(".java")});
詳しくは、"doc"に Javadoc、"src.sample"にサンプルソースがありますので、そちらを参照してください。
net.argius.frui.Operationインタフェースを実装したクラスを作成すると、evaluateオプションで使用することが出来ます。
evaluateオプションはパラメータ数が可変になっています。次のように指定することができます。
例: $ frui -e 3 localhost.Evaluator A B C →localhost.Evaluatorクラスの引数が3のコンストラクタが呼ばれる
Fruiは、Java1.4から導入されたjava.util.regexパッケージと、それを利用するjava.lang.Stringクラスの新しいメソッドを利用しているため、Java1.3ではコンパイルできません。但し、正規表現に関する処理は依存性を切り出していますので、そこをサードパーティの提供している正規表現ライブラリに切り替えれば使えるようになると思います。
"src.forJava1.3"に、Jakarta-Regexを使用した例がありますので参考にしてください。(pattern#replace()を利用する機能は対応していません。)
2008 argius