一昨日書いたコードに追記して、結果をファイルに記録してみるようにしてみた。複数のプロセスで1つのファイルに書き込むのもMutexとか使わずに簡単に書けたのでびっくりした。
% % grep.erl -- find patterns from multiple files % % usage: % (erl)>grep:main({filename, pattern, [file1, file2, file3, ..]) % % version 0.2 % % todo: % 1. exception processing for invalid arguments. % 2. launch grep() as a server % 3. show line number if option is handed to arguments % -module(grep). -export([main/1]). -compile(export_all). main({LogFile, Pattern, Files}) -> ets:new(tfile, [public, named_table, bag]), ets:insert(tfile, {"logfile", LogFile}), lists:map(fun(F) -> filep(Pattern,F) end, Files). filep(Pattern, File) -> case file:open(File, [read]) of {ok, Fd} -> ets:insert(tfile, {Fd, File}), spawn(grep, loop, [Pattern, Fd]); {error, Reason} -> io:format("~s : ~s", [error, Reason]) end. loop(Pattern, Fd) -> case file:read_line(Fd) of {ok, Line} -> case re:run(Line, Pattern) of {match, _} -> [Head | _] = ets:lookup(tfile, "logfile"), {_, LogF} = Head, {ok, Logd} = file:open(LogF, [append]), [Filet | _] = ets:lookup(tfile, Fd), {_, File} = Filet, Log = File ++ " -> " ++ Line, {ok, TailPosition} = file:position(Logd, eof), file:pwrite(Logd, TailPosition, Log), file:close(Logd); nomatch -> ok end, loop(Pattern, Fd); eof -> file:close(Fd); _ -> ok end.
若干気になるのはets:lookup/2では{key, value}のObjectを返してしまうので、いちいちパターンマッチでvalueを取り出してるけど、これはすごくスマートじゃないし、絶対f(key) -> valueってなるような関数があるはずだよなあ。
ご指導願います。