- ベストアンサー
ログファイルからキーワードを検出、何行目か返す。
以前こちらでおなじような質問をして回答いただいたのですが、どうしても理解できないので再度質問させていただきます。 フォームで名前や件名などを入力してもらい、その入力データをログファイルへ入れます。 ログファイルは以下のような感じのものが何行も続いています。 NAME=hoge&TITLE=tatoeba&NAKAMI=konnnakanji&LOCALTIME=20030127094224= (LOCALTIMEだけは自動で入るようになっています。) その後で、このログファイルから任意の行を取り出したいのですが、削除されることもあるため○行目という値では意図するものが出てこない可能性もあるので、 LOCALTIMEで検索をしたいのです。 20030127094224と入れた場合、ログファイルの○行目、と判定するようなことをしたいのです。 どのようにしたらいいのかさっぱりわかりません。 よろしくお願いします。 #perlです。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
急いで書いたら一部訂正です。。 ## $nnは行をカウントする為に設定します $nn=0; ## ログを1行ずつ読み込みます。行が存在する分、繰り返します。 foreach $line (@lines){ ## 読み込んだ行を 「&」で区切り$NAME $TITLEなどに格納します。 ($NAME,$TITLE,$NAKAMI,$LOCALTIME) = split(/&/,$line); ## $LOCALTIMEは そのままでは「LOCALTIME=」という文字を含んでいるので、10文字目から最後までの文字を$LOCALTIMEと設定し直します。 $LOCALTIME=substr $LOCALTIME,10; ## ちょっと訂正しました。もし検索ワードとLOCALTIMEが同じであれば、このループを抜け出します。 if($検索ワード eq $LOCALTIME){last;} ## 検索ワードとLOCALTIMEが違う場合は$nnに1を足します。 else{$nn++;} ##繰り返し部分を閉じます } ループを抜け出すのを忘れていたので 一部訂正して $nnに行数が入るようになりました。 あと$LOCALTIMEのすぐ後ろに改行があるので(ログの各行は改行されてますよね?) それを取り除かないとヒットしないかもしれません。
その他の回答 (3)
- angelusbell
- ベストアンサー率33% (3/9)
自己流なので 回りくどいかもしれませんが open(IN,".ログファイル") @lines = <IN>; close(IN); $nn=0; foreach $line (@lines){ ($NAME,$TITLE,$NAKAMI,$LOCALTIME) = split(/&/,$line); $LOCALTIME=substr $LOCALTIME,10; ##「LOCALTIME=」の文字を除く if($検索ワード eq $LOCALTIME){$gyou=$nn;} else{$nn++;} } これで何行目というのが $gyouに入るはずです
- osamuy
- ベストアンサー率42% (1231/2878)
> /^NAME=.+&LOCALTIME=[0-9]+=/ > はどのような意味でしょうか? 大雑把に言えば、「NAME=」から始まり、途中から「&LOCALTIME=」、直後にいくつかの数字、そして文字「=」を含む文字列に一致するパターンを表してます。 詳しい事は、Perlの書籍や正規表現についての書籍などをご覧ください。 スクリプトを大雑把に言えば、 ・コマンドラインの第一引数を日付け指定とする検索パターンを作成。 ・ログ配列を先頭から順に見てゆき、検索パターンに一致するものがあったら、結果変数に格納。 ・結果変数の中身が空でなければ、検索にHitしたということで、それを表示、空なら見つからなかったと報告。 ――ってところです。 正規表現引用演算子qr以外は、Ver.4のPerlでも動くようなスクリプトです。 正規表現を使わなくたって、index()とかでも検索部の条件判断は記述できますね。 キーワードで不明なのがありましたら、Perl付属のマニュアルperlfuncかperlopをご覧下さい。 またサンプルスクリプトを実行してみて、各変数の内容をprintで出力してみたり、正規表現パターンを変更したら挙動がどう変わるかを実験してみると、理解が早まるかと思います。
- osamuy
- ベストアンサー率42% (1231/2878)
> NAME=hoge&TITLE=tatoeba&NAKAMI=konnnakanji&LOCALTIME=20030127094224= この形式で、LOCALTIMEで検索するなら、 /^NAME=.+&LOCALTIME=[0-9]+=/ みたいな、正規表現で引っ掛けられるかと。 以下は実験。Mac OS X 10.2.3+perl v5.6.0で試してます: % cat a.pl $arg = $ARGV[0]; @Log = <DATA>; $find_pattern = qr|^NAME=.+&LOCALTIME=${arg}\d*=|; $find_line = ''; $find_lino = $lino = 0; for ( @Log ){ $lino++; next unless $_ =~ $find_pattern; $find_line = $_; $find_lino = $lino; last; } if ( $find_line ne '' ){ print $find_lino, ': ', $find_line, "\n"; } else { print $arg, " not found.\n"; } __END__ NAME=hoge&TITLE=tatoeba&NAKAMI=konnnakanji&LOCALTIME=20030127094224= NAME=hoge&TITLE=test&NAKAMI=konnnakanji&LOCALTIME=20021107095959= % perl a.pl 200301 1: NAME=hoge&TITLE=tatoeba&NAKAMI=konnnakanji&LOCALTIME=20030127094224= % perl a.pl 200201 200201 not found. 削除されたものを除外するには、ループの中で$linoをインクリメントする前に、スキップさせるとか。
お礼
回答ありがとうございます。 せっかく回答いただいたのですが、私には理解ができません…。 まず /^NAME=.+&LOCALTIME=[0-9]+=/ はどのような意味でしょうか? その後のコードもわかりません。 申し訳ございませんが、解説いただけるとありがたいです。 よろしくお願いします。
お礼
回答ありがとうございます。 ちょっと自分なりにアレンジしてみてこんな感じにしてみました。 print "Content-type:text/html\n\n"; open(FILE, "teian.log"); @logfile = <FILE>; close(FILE); #行をカウントするためのもの。 $i = 0; @log = split(/&/,$logfile[$i]); foreach (@log){ $log[$i] =~ s/\n$//; @logs = split(/&/,$_); # $logs[$i] =~ s/\n$//; ($key,$value) = split(/=/,$_); $FORM{$key} = $value; # $FORM{'LOCALTIME'}=substr('$FORM{'LOCALTIME'}',19); ##[$FORM{'LOCALTIME'}=の文字を除く if($searchvalue eq $FORM{'LOCALTIME'}){ print "あってるよ。\n"; print "<FONT COLOR=BLUE>$FORM{'LOCALTIME'}</FONT>\n"; last; }##あっていればループを抜ける else {$i++;} } 1番最初のログのLOCALTIMEで検索するときちんと「あってるよ」と出るのですが、2つ目、3つ目、となるとできません。 誤りのご指摘お願いします。