さ み だ れ 雑 記 | 86 | 2010年4月21日 |
アクセスログをperlでCSV化する。
あ〜。perlは久しぶりです。
すっかり忘れていました。
このサイトを立ち上げた時、とほほさんのWwwCounterを使わせてもらってアクセスカウンターを設置しました。
このアクセスカウンター、毎日(新しいアクセスがあれば)前日の記録をメールで知らせてくれます。
Subject: ACCESS 110/04/16 69
Date: 17 Apr 2010 01:20:46 +0900
From: kall@***.***
To: ***@*****.***
COUNT = [ 108426 ]
DATE = [ 110/04/16 ]
TIME = [ 00:24:39 ]
ADDR = [ 210.198.154.20 ]
HOST = [ ]
AGENT = [ Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) ]
REFER = [ http://office-kawakami.com/kawa_s/zakki_02/zakki_078.html ](略)
こんな感じです。
このメールが貯まって貯まって。
まあ、別にしみじみと見ることもないから、削除してもかまわないんですが、なんか累計10万も超えていると、何とはなしに勿体ないような。
けど、メーラーに貯めておくと、
こんな警告を出すんですよね。放置してましたが、いつまでも放置するのも。
ということで、この貯まりに貯まったアクセスログをCSVファイル化してやろう、と。それで貯まりに貯まったメールを削除するぞ、と。
♪
実際は、アクセスログをperlを使ってCSVファイル化するプログラム、作ってたんですよね。5〜6年前に。
しかし、なんらかの理由で行方不明。削除しちゃったらしいんですよ。それに気がついたのが数年前。
で、面倒だなあ、で、またまた数年間、放置。
そろそろ作ろうか、で重い腰を上げたら、さっぱり分からん!
本当に俺は、「アクセスログをperlを使ってCSVファイル化するプログラム」なるものを作っていたのだろうか、と疑いたくなるような、五里霧中状態。
ひー、ひー言って、それでも、動作するものが出来た時には、思わず顔がほころびましたね、目出度し、目出度し。
ということで、健忘録のつもりで書いてますんで、プロから見れば、もっと、綺麗に書けるのに、みっともないと言われるかも知れんですが、まあ、それはそれ。
♪
メーラーはEdMaxフリー版を使っています。これは、メールをmbxという拡張子のファイルにまとめますが、このmbxファイルは、テキストファイルなので、それをperlで読み込んで、CSVに加工して、書き出そう、という魂胆でございます。(メーラーによってはバイナリーファイルとして纏められているかもしれません。そういった方は、何らかの方法でバイナリーをテキストに変換してください。)(バイナリーって何じゃいという方は検索してお調べ下さい。ご勘弁。)
ひょっとしたら「アクセスログ CSV」などと検索して、perlを使ったことがまったく無い方が訪れるかもしれませんが、1からの懇切丁寧な説明はできませんです。
コマンドラインでperlを動かせるぐらいを前提とさせていただきます、です。
まあ、最終的には没になった部分も含め、くどくどと記述するつもりですので、せっかちな方はど〜んと後ろへ 飛んでください。
♪
まず、ファイルの読み込み。
open(IN, "datafile.txt");
@xx = <IN>;
foreach $yy (@xx) {
print $yy;
}
close(IN);とほほのperl入門からですが、上のように記述すると、「ファイルの各行を配列に一括して読み込む」んだそうです。
INは、ファイルハンドルと呼ばれています。任意の大文字でいいようですが、読み込むのだから、INがいいでしょう。
@を用いて「配列全体や配列の範囲を表現する」んだそうです。
$で始めるのは、スカラー変数と呼ばれ、数値や文字列を代入できるそうです。
また、「$変数名[添え字]という形式で配列を表現することができます。添え字には0,1,2,3...を指定します。」とのことです。実際、私は、@と$の違いがよう分かっていません。動いたら結果オーライという安直さです。だって、素人なんだもん!
open(OUT, "> datafile.txt");
print(OUT "こんにちは\n");
close(OUT);
これがファイル書き出し、です。open(OUT, "> datafile.txt");は上書き(あるいは新規書き込み)の場合で、既存のファイルに追加書き込みする場合はopen(OUT, ">> datafile.txt");
のようにします。
♪
ちょっと、脱線気味ですが、print。
これ多分、コンピューターの標準出力がモニター画面ではなく、パンチカードっていうんですか、ま〜、紙にプリントアウトしていたころからのプログラム用語じゃないか、と、素人なりに推測しているんですが、どうなんでしょうかねえ。コンピュータ言語の基本紹介の定番として、「Hello World!」を表示する、ってのがありますが、perlでは
perl -e "print 'Hello World!';"
とコマンドラインで打ち込んだり、print "Hello World!\n"; という内容のhello.pl たらいう名前のファイルでも作ってperl hello.pl
とタイプすると、モニター画面に、「Hello World!」と表示されるんですが、モニター画面に表示するのを何故に print ?
と考えていくと、これはやはり紙に印刷していた時代からの名残ではないのだろうか、と。ということで、上の
open(IN, "datafile.txt");
@xx = <IN>;
foreach $yy (@xx) {
print $yy;
}
close(IN);これを perl ファイル名.pl でエンターすると、datafile.txtの中身を画面表示します。
open(OUT, "> datafile.txt");
print(OUT "こんにちは\n");
close(OUT);こっちの print(OUT "こんにちは\n"); の方は、画面表示するんじゃなくて、OUTというファイルハンドルの中に「こんにちは\n」を書き込む、っていうか格納します。(\nは改行をあらわします)
ということで、上の二つを合体します。
open(OUT, "> out.txt");
open(IN, "in.txt");
@xx = <IN>;
foreach $yy (@xx) {
print(OUT $yy);
}
close(IN);
close(OUT);
これは、in.txtを開き、INに入れさらに@xxにいれ、それを一行づつ$yyに取り出して、printを使ってOUTに格納し、out.txtに出力する。
つまり結果としては入力したin.txtと同じ内容のout.txtを出力します。おお!ひとつの大きな山を越えたぞ!
♪
次の大きなる山は、必要な部分だけ、取り出す作業である。
下のアクセスカウンターのログから
Subject: ACCESS 110/04/16 69
Date: 17 Apr 2010 01:20:46 +0900
From: kall@***.***
To: ***@*****.***
COUNT = [ 108426 ]
DATE = [ 110/04/16 ]
TIME = [ 00:24:39 ]
ADDR = [ 210.198.154.20 ]
HOST = [ ]
AGENT = [ Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) ]
REFER = [ http://office-kawakami.com/kawa_s/zakki_02/zakki_078.html ](略)
最終的には
108426,110/04/16,00:24:39,210.198.154.20,Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729),http://office-kawakami.com/kawa_s/zakki_02/zakki_078.html(改行)
こういう風にコンマで区切られたCSV形式で取り出したいのである。
まず、COUNT = [ 108426 ] から考えよう。同じくとほとさんのリファレンスを探すと、「文字列比較演算子」に下のような書式がある
if ($xx =~ /ABC/) # $xxがABCという文字を含んでいれば これを使って、if ($xx =~ /COUNT/)とやれば
COUNT = [ 108426 ] この部分にたどり着くはずである。あとは、ここから「108426」だけを取り出せればいい。
ど〜やって? なのであるが、ここで「正規表現」の登場とあいなるのである!
♪
正規表現は、日常的にプログラムする人は自然に暗記するのであろうが、思い出したように数年に一度プログラムするようなら、完璧忘れる。
じゃによって、健忘録をかねてとほほさんとこから、引用させていただこう。
A Aという文字
ABC ABCという文字列
A+ 1個以上連続したA(A, AA, AAA, ...)
A* 0個以上連続したA( , A, AA, AAA, ...)
. 1つの任意文字(A, B, C, ...) (\nを除く)
A? 0または1つのA( , A)
^ABC ABCで始まっていたら
ABC$ ABCで終わっていたら
[ABC] A,B,Cのいずれか1文字
[A-Z] A〜Zまでのいずれか1文字
[A-Za-z0-9] A〜Z, a〜z, 0-9までのいずれか1文字
[^ABC] A,B,C以外の文字
[^A-Z] A〜Z以外の文字
A|B|C AまたはBまたはC
\w 英数文字かアンダーバー( _ )。[a-zA-Z0-9_]と同様
\W \w以外の文字
\d 数値文字。[0-9]と同等
\D \d以外の文字
\s 空白文字
\S \s以外の文字
\b 単語の区切り??????
\B \b以外の文字
\nなど エスケープシーケンス文字の\nなど
(ABC) ABCという文字列。カッコ部分は後で参照可能です。
正規表現中では下記の文字は特殊な文字(メタ文字)として扱われますので、これらの文字を表わすには \+, \*, \?, ...のようにします。
+ * ? . ( ) [ ] { } | \
\d 数値文字。[0-9]と同等 というのが使えそうであるが、必要なものだけ取り出す、のは、よう分からん。必要でないのを取り除く、方が、perlでは簡単にできるようである。文字列置換を使う。
次の例は、文字列$xxの中の abc という文字列をすべて大文字の ABC に変換します。最初の s は置換することを表わします。最後の g を省略した場合は、最初に現れたabcを1度だけ置換します。
$xx =~ s/abc/ABC/g;
ここで、上をアレンジして
$xx =~ s/abc//g;
とすると、文字列$xxの中の abc という文字列をすべて削除するのである。
♪
ということで、試作したのが、下である。 (\D は数字以外の文字) (この箇所は、最終的には、没。)
open(OUT, "> out.txt");
open(IN, "01.mbx");
@xx = <IN>;
foreach $yy (@xx) {
if ($yy =~ /COUNT/){
$yy =~ s/\D//g;
print(OUT $yy);
}
}
close(IN);
close(OUT);COUNTという文字が含まれる行なら、そこの数字以外の文字をどんどん削除していくのである。で、動かしてみると・・・・。
1084261084271084281084291084301084311084321084331084341084351084361084371084381(略)
とまあ、 $yy =~ s/\D//g; では改行コードまで削除してしまうのであった!素人がプログラムすると、まあ、こういった、無理難題ちゅうか、あんれまあ、そげーなことが・・・山のように起こるのである。
こういうトラブルをひとつひとつ克服していくのである。
open(OUT, "> out.txt");
open(IN, "01.mbx");
@xx = <IN>;
foreach $yy (@xx) {
if ($yy =~ /COUNT/){
$yy =~ s/\D//g;
print(OUT "$yy\n");
}
}
close(IN);
close(OUT);
結局、上の修正をへて無事
108426
108427
108428
108429
108430
108431
108432
(略)
と切り出せるようにはなったのであるがprint(OUT $yy\n);
と表記したのでは、syntax errorがある、とかいうクレーム出して動かないのである。print(OUT "$yy\n");
と表記すると、動くのである。\nは改行コードを表現するのであるが、これも文字だから、という理由なんでしょう。たぶん。 素人にはこの程度のことを解決するのにも結構時間がかかったりするのである。
♪
気を取り直して、次
DATE = [ 110/04/16 ]
TIME = [ 00:24:39 ]
ADDR = [ 210.198.154.20 ]
HOST = [ ]
AGENT = [ Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) ]
REFER = [ http://office-kawakami.com/kawa_s/zakki_02/zakki_078.html ](略)
今度は、COUNT = [ 108426 ]のように、取り出したいものが、数字だけではない。文字もある。
if ($yy =~ /TIME = [ /){
$yy =~ s/TIME = [ //g;
などといったことをしたら・・・・多分スペースが入るのが問題なのであろうが、うまくいかないのである。TIMEを削除し、スペースを削除し、=を削除し、スペースを削除し、[を削除し・・・スペース嫌い・・・・。あ、俺バカだなあ。/g にしてるから、一度だけ記述すれば、全部のスペースが消えるじゃん!
ということで: (この箇所も、最終的には、没。)
open(OUT, "> out.txt");
open(IN, "01.mbx");
@xx = <IN>;
foreach $yy (@xx) {
if ($yy =~ /COUNT/){
$yy =~ s/\D//g;
print(OUT "$yy,");
}elsif ($yy =~ /TIME/){
$yy =~ s/TIME|=|\[|\]|\s//g;
print(OUT "$yy\n");
}
}
close(IN);< BR > close(OUT);TIME|= |\[|\]|\s
| は文字区切りです。
[ はメタ文字と呼ばれる文字なので、[ そのものを表すには \[ と表記します。(]も同様です)
\sは空白を表すのですが、これを使うと、改行コードも消えます。ま、これで無事、下のように取り出せました。
108426,00:24:39
108427,00:41:16
108428,01:16:23
108429,02:24:33
108430,06:28:32
108431,06:47:15
108432,07:37:30
108433,07:59:19
108434,08:53:58
108435,08:56:17
(略)
あとは、以下同様。 ・・・・・じゃなかったんだよなあ。 はあ〜。
$yy =~ s/AGENT|=|\[|\]|\s//g;
だと、スペースをすべて削除してしまうから
AGENT = [ Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) ]
は、
Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1;GTB6.4;.NETCLR2.0.50727;.NETCLR3.0.4506.2152;.NETCLR3.5.30729)
となるんですよね。
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
でいいのに・・・・。
それに、REFER。物によっては
<p>REFER=[http://webcache.googleusercontent.com/search?q=cache:x6xnMcOdJpoJ:office-kawakami.com/kawa_s/zakki/zakki_001.html+ファイルを開く パスを通&cd=38&hl=ja&ct=clnk&gl =jp ] < /td> < /td> < /td> < /td> < /td> < /td> < /td> < /td> こんなのがあるんですよね。「=」が含まれているんですよ。
http://webcache.googleusercontent.com/search?qcache:x6xnMcOdJpoJ:office-kawakami.com/kawa_s/zakki/zakki_001.html+ファイルを開く パスを通&cd38&hlja&ctclnk&gljp
「=」がすべて消えちゃいますね〜。
けっきょく、地道が一番、ということか・・・。
if ($yy =~ /TIME\s=\s\[\s/){
$yy =~ s/TIME\s=\s\[\s//;結局、ちょっと前に
if ($yy =~ /TIME = [ /){
$yy =~ s/TIME = [ //g;
などといったことをしたら・・・・多分スペースが入るのが問題なのであろうが、うまくいかないのである。などと書いた、そのスペースと[ を処理すれば、それで正解だったのである。はあ。
さて、気を取り直して。
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) ]
残った、「末尾のスペース+]」の処理。
ABC$ ABCで終わっていたら
を使って
$yy =~ s/\s\]$//;
解決。
♪
と、ここら辺で、配列に挑戦してみようかなあ?という気が沸々と。if (条件1){
処理1
}elsif (条件2{
処理2
}elsif (条件3){
処理3
}とかいった構文で、おのおのの処理1・2・3が異なるのならともかく、今回、処理は統一しようと思えばできるわけです。処理1だけ数字しか使われていないという理由で別処理しましたが、他の処理は、結局地道な処理になってしまって、この地道路線は、もちろん最初の数字だけの場合も正しく処理します。
ということはif (条件1から6){
同じ処理
}
この「条件1から6」という部分を配列で処理すれば、elsif を何度も使って場合わけする必要はない。基本を地道にやっておけば、他で楽が出来るってことでしょうか?
♪
配列は
$array[0] = "COUNT";
$array[1] = "DATE";
$array[2] = "TIME";
$array[3] = "ADDR";
$array[4] = "AGENT";
$array[5] = "REFER";foreach $aa (@array) {
print "$aa\n";
}
こんな感じで使えばいいでしょう。
こいつと下の奴を合体する。
open(OUT, "> out.txt");
open(IN, "01.mbx");
@xx = <IN>;< BR >
foreach $yy (@xx) {
if ($yy =~ /TIME\s=\s\[\s/){
$yy =~ s/TIME\s=\s\[\s//;
$yy =~ s/\s\]$//;
print(OUT $yy);
}
}
close(IN); <BR>close(OUT);
と、いうことは・・・・・。
$array[0] = "COUNT";
$array[1] = "DATE";
$array[2] = "TIME";
$array[3] = "ADDR";
$array[4] = "AGENT";
$array[5] = "REFER";open(OUT, "> g01.csv");
open(IN, "01.mbx");
@xx = <IN>;
foreach $yy (@xx) {foreach $aa (@array) {
if ($yy = ~ /$aa\s = \s\[\s/){
$yy =~ s/$aa\s=\s\[\s//;
$yy =~ s/\s\]$//;
print(OUT $yy);
}}
}
close(IN);
close(OUT);こんな感じ。
で、大筋はこれで出来ましたが、まだまだ微調整が。
まず、要素ごとに改行されちゃいました。また、CSVファイルに変換するためのコンマも入ってません。これは
if($aa ne $array[5]){
$yy =~ s/\n/,/;
}
配列の最後の要素でなければ改行をコンマに変換してねというif文を入れて解決。
さらに、
Subject: ACCESS 110/04/16 69
Date: 17 Apr 2010 01:20:46 +0900
From: kall@***.***
To: ***@*****.***
COUNT = [ 108426 ]
DATE = [ 110/04/16 ]
TIME = [ 00:24:39 ]
ADDR = [ 210.198.154.20 ]
HOST = [ ]
AGENT = [ Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) ]
REFER = [ http://office-kawakami.com/kawa_s/zakki_02/zakki_078.html ](略)
何故かTIME、ADDRの行が無視される。
何故じゃ、何故なんじゃ〜!もとのデータをよく見たら、問題のTIME、ADDRの後にはスペース2字。他は1字。そ、そんなんまでありか?
元の
$yy =~ s/$aa\s=\s\[\s//;
を、
$yy =~ s/$aa\s+=\s\[\s//;
と書き換えて解決。
A+ 1個以上連続したA(A, AA, AAA, ...)
Bravo! 正規表現! Bravo!
♪
これで出来た!などと、思っていたら、やはり、案の定。そうは問屋が卸さない。
AGENT = [ Mozilla/5.0 (en-us) AppleWebKit/525.13 (KHTML, like Gecko; Google Wireless Transcoder) Version/3.1 Safari/525.13,Mozilla/5.0 (en-us) AppleWebKit/525.13 (KHTML, like Gecko; Google Wireless Transcoder) Version/3.1 Safari/525.13 ]
REFER = [ http://office-kawakami.com/kawa_s/zakki_02/zakki_072.html ]
と、あちらこちらにコンマが・・・。これで、エクセルなんかで開くと、しっかりCSVの区切りのコンマと解釈されます。
ということで、
$yy =~ s/,/;/g;
を追加し、元々存在するコンマは、セミコロンに変換することでお茶を濁しました。(要素をダブルクオーテーションでくくれば解決しそうですが、めんどうくさい。)
あとおまけをつけて、一応の完成版は以下のようになりました。
ファイル名は一応アクセスログなのでalかなあ、と、al.pl
#アクセスログから必要部分を抜き出すperl
#用法:perl al.pl 入力ファイル名 出力ファイル名
#
# 特定の文字列で始まる行から、不要部分を削除する。
# 例えばCOUNT = [ 108426 ]なら
# 「COUNT」を、$array[ ]で指定、「 = [ 」を$omakeで指定、末尾の「 ]」を$matubiで指定している。
#2010/4/20 by K's Korner
$array[0] = "COUNT";
$array[1] = "DATE";
$array[2] = "TIME";
$array[3] = "ADDR";
$array[4] = "AGENT";
$array[5] = "REFER";$omake = '\s+=\s\[\s';
$matubi = '\s\]';
if($ARGV[0] eq ""){
print "用法:perl al.pl 入力ファイル名 出力ファイル名\n";
print "空白を含むファイル名の場合:perl al.pl \"入力ファイル名\" \"出力ファイル名\"\n";
} else {
open(IN, "$ARGV[0]");
open(OUT, ">$ARGV[1]");
@xx = <IN>;foreach $yy (@xx) {
foreach $aa (@array) {
if ($yy =~ /$aa$omake/){
$yy =~ s/,/;/g; #元データにコンマがあるとCSVが誤作動するのでセミコロンに変換する
$yy =~ s/$aa$omake//;
$yy =~ s/$matubi$//;
if($aa ne $array[-1]){
$yy =~ s/\n/,/;
}#最後の要素以外は、改行をコンマに変換する。print(OUT $yy);
}#if ($yy =~ /$aa$omake/)の終わり
}#2番目のforeachの終わり
}#最初のforeachの終わり
close(IN);
close(OUT);
}#最初のif else の終わり
$ARGV[0] は引数を格納する変数だそうです。perl al.pl 引数1 引数2 をそれぞれ、$ARGV[0], $ARGV[1] で呼び出します。
if($ARGV[0] eq "")のところは、引数が指定されていなかったら、の意味です。エクセルやMS-DOSのバッチファイルでは""で何も無いことを意味するので、perlもそうかな、と書いたら動いたのでそれでいいのでしょう。
最初の引数が指定されていなかったら、用法:perl al.pl 入力ファイル名 出力ファイル名
空白を含むファイル名の場合:perl al.pl "入力ファイル名" "出力ファイル名"と表示し終了します。(ActivePerl V5.10.1では、perl を省略し al.pl 入力ファイル名 出力ファイル名 で動くようです。そういえば、インストールのときそれらしきチェック項目があったような)
ここの部分、if($ARGV[0] == "")と記述すると、ファイル名が数字で始まらないとうまく動作しません。調べると、
eq 文字列として処理
== 数字として処理という違いがありました。同様に、
ne 文字列として処理
!= 数字として処理なので、if($aa ne $array[-1])の箇所も if($aa != $array[-1]) と記述すると、こちらの望む結果は出ません。ああ、奥が深い。
改造しやすいように、\s+=\s\[\sの部分は、$omakeという変数に代入しました。この場合、ダブルクオーテーションで代入すると、動作しません。
これは「ダブルクォーテーションの中では変数やバックスラッシュ( \ )が評価され」るからだそうです。「シングルクォーテーションの中では単なる文字として認識され」るということで、シングルクオーテーションで代入します。
同様に、末尾の「 ]」の部分も $matubi = '\s\]'; という形で処理しました。
また、配列の最後の要素の指定方法を、 $array[5]から、$array[-1]に変更しました。(-1が最後の要素、-2は最後から数えて2番目の要素)
改造した結果、最後の要素が、$array[4]になろうが、$array[10]になろうが、 $array[-1]で指定しておけば、変更なしですみます。
小幅なカスタマイズなら$array[0] = "COUNT";
$array[1] = "DATE";
$array[2] = "TIME";
$array[3] = "ADDR";
$array[4] = "AGENT";
$array[5] = "REFER";$omake = '\s+=\s\[\s';
$matubi = '\s\]';この部分だけの変更で使えそうな感じです。
動作確認は、Windows XP, Vista, ActivePerl V5.10.1で行っています。(入力するファイルはテキストファイルである必要があります)
参考までにダウンロードal.lzhできます。よかったら、どんどん改造してください。
open(IN, "$ARGV[0].mbx"); |
例えば上のように改造したら、perl al.pl メールボックスファイル名(拡張子省略) でメールボックスファイル名.csv ファイルを自動生成します。こっちの方が、楽チンかなあ?汎用性には乏しくなりますが・・・。
まあ、楽チンといえば、下のようなバッチファイルを使った方が楽チンかと思います。al.batという名前だとすると、perl al.pl と入力すべきところが、al だけですみますから。
(空白を含むファイル名の場合は使えません。al "K's ALL.mbx" とすると ALL.mbx""== "/?" の使い方が誤っています。と叱られます。perlが省略可能となると、.pl がいらないだけの楽チンです。せっかく作ったのに、ちょっと悲しいぞ。)
@echo off
if "%1"=="/?" goto help
if "%1"=="" goto help
perl al.pl %1.mbx %1.csvgoto exit
:help
echo.
echo アクセスログをCSVファイルに変換します。
echo 変換元ファイル(.mbx)を拡張子なしで指定してください。
echo.:exit
では、また。(バッチファイル書くの何年ぶりだろう?)![]()