BATCH ROOM バッチルームへようこそ!

 日夜バッチファイルに心血を注ぎつづけている皆さんに送る愛のメッセージ!(自爆)
 なにかの参考になれば幸いです。
(このページのタイトル、BUの活用ページってしたほうがいい?)

便利な道具達
BU
言わずと知れたPaci氏作のバッチファイルユーティリティ「BU」です。 これなくして私のバッチ野郎人生は始まりません...(笑)
text utilities
UNIX text utilities同等のフィルタ関連のtools。アスキーのsoftware tools、 GNUのやつなど何でもok。私は新出尚之氏の「UNIX-like tools」 を使わせていただいています。
sed
ストリームエディタの「sed」です。バッチ野郎には必携ツールです。 今すぐヘビ使い、じゃない「sed使い」になりましょう。また、 いざというときの万能フィルタ(?)「awk」も操れると安心です (本当はperlで見得を切りたいところですが勉強不足です(苦笑))。ちなみにsedは 「LOGOS版」を使用しています。
ygrep
YOT氏作「ygrep」です。LZHの中まで探しにいってくれるので便利です。
FD
泣く子も黙る、泣いた子はもっと泣き出す(笑)超定盤ファイラー、A.Idei氏作 「FD55/FDPC」です。ユーザコマンドが登録でき(当然バッチも登録するんですよ)、 バッチ野郎にはたまりません。私としてはロングファイルネーム対応の 「FD95(仮称)」の登場を切に願っている毎日です。
wsh
マイクロソフト御謹製のwindows世代のスクリプト言語。 正規表現が使えるとあって、注目しているところです。

CASE 10:モデムのログを集計したい場合

 パソコン通信時代には、あれほど気にしていた通信費。インターネットな現在、 怠惰にまかせてアクセスしていますが、実際のところどのくらい使っているのかなぁ、 なんて思ったりして。契約しているプロバイダの請求をみれば、 15h以上は使っているのは確かだが、電話料金はどうなっているのだろう?。 テレホーダイするほど夜型生活でないので、 かろうじてタイムプラス当ててアナログ回線でニンパパ通信、 しかもi486DX4/100MHzで激遅IE3.02、いざという時のネスケ4.04(これも古いか?) という通信環境でがんばっている訳です。
 で、一応モデムのプロパティでログをとるようにしてあるので、 そのログを使って集計してみました。
mdmlog.bat / mdmlog.sed / mdmlog1.bat / mdmlog1.awk / mdmlog1.vbs
 mdmlog.batはmdm.logというログファイルを出力します。形式は 「アクセク開始日時 アクセス修了日時 アクセス時間」でこんな感じ。

1998-05-09 13:57:46 1998-05-09 14:15:09 00:17:23

 mdmlog1.batはmdm.logを元に、今月の接続回数、接続時間(日中、夜間別)、 通話料(タイムプラスを使用した場合の料金)、 月平均接続時間に対する今月の割合を表示します。
list mdmlog.bat
if not exist c:\windows\modemlog.txt goto end
cat c:\windows\modemlog.txt >>c:\windows\modemlog.bak
sed -f mdmlog.sed c:\windows\modemlog.txt >$mdmlog.bat
call $mdmlog
del $mdmlog.bat
del c:\windows\modemlog.txt
:end
list mdmlog.sed
/ATDT\#/{
  s/\(..\)\-\(..\)\-\(....\) \(..\):\(..\):\(..\).*/\3 \1 \2 \4 \5 \6/
  h
  :loop
  ${
    x
    s/\(....\) \(..\) \(..\) \(..\) \(..\) \(..\)/echo \1\-\2\-\3 \4:\5:\6 error\>\>mdm.log/
    q
  }
  N
  s/.*\n//
  /ATDT\#/{
    s/\(..\)\-\(..\)\-\(....\) \(..\):\(..\):\(..\).*/\3 \1 \2 \4 \5 \6/
    x
    s/\(....\) \(..\) \(..\) \(..\) \(..\) \(..\)/echo \1\-\2\-\3 \4:\5:\6 error\>\>mdm.log/
    p
    d
    b loop
  }
  /NO CARRIER/{
    s/\(..\)\-\(..\)\-\(....\) \(..\):\(..\):\(..\).*/ \3 \1 \2 \4 \5 \6/
    H
    x
    s/\n//
    s/^/command \/c lap \-l /
    s/$/ \>\>mdm.log/
    b
  }
  b loop
}
d
list mdmlog1.bat
jgawk -f mdmlog1.awk mdm.log >$mdmlog1.txt
start mdmlog1.vbs
list mdmlog1.awk
BEGIN{
  FS=" "
  day=8*60
  night=23*60
  bm=0
  totaltime=0
  totalcount=0
}
{
  m=substr($1,6,2)*1
  d=substr($1,9,2)*1
  if(bm == 0){
    bm=m
    by=substr($1,1,4)*1
  }
  if(bm != m){
    totalcount++
    totaltime=totaltime+monthtime
    by=substr($1,1,4)*1
    bm=m
    nosum1=0
    tpsum2=0
    daytime=0
    nighttime=0
    monthtime=0
    d_count=0
  }
  if($2 != "error"){
    d_count++
    mm0=substr($3,1,2)*60+substr($3,4,2)+sgn(substr($3,7,2)*1)
    smm0=substr($1,12,2)*60+substr($1,15,2)
    emm=substr($2,33,2)*60+substr($2,36,2)
    count1=0
    mm=mm0
    smm=smm0
    rate=0
    while(sgn(mm) > 0){
      if((smm >= day) && (smm < night)){
        rate=3
        daytime=daytime+rate
      }else{
        rate=4
        nighttime=nighttime+rate
      }
      smm=smm+rate
      if(smm >=1440)smm=smm-1440
      mm=mm-rate
      count1++
    }
    mm=mm0
    smm=smm0
    count2=0
    rate=0
    while(sgn(mm) > 0){
      if((smm >= day) && (smm < night)){
        rate=7
      }else{
        rate=5
      }
      smm=smm+rate
      if(smm >=1440)smm=smm-1440
      mm=mm-rate
      count2++
    }
    nosum1=nosum1+count1*10
    tpsum2=tpsum2+count2*10
    monthtime=daytime+nighttime
  }else{
  }
}
END{
  printf "%4d年%2d月%2d日現在\n接続回数 %2d回\n接続時間 %s(Day %s / Night %s)\n通話料 %4d円(タイムプラス使用時 %4d円)\n",by,bm,d,d_count,hhmmss(monthtime),hhmmss(daytime),hhmmss(nighttime),nosum1,tpsum2
  printf "対月平均接続時間(%s)率%3d%%\n",hhmmss(sprintf("%d",totaltime / totalcount)),(monthtime / sprintf("%d",totaltime / totalcount))*100
}
function sgn(n){
  if(n == 0){
    return 0
  }else if(n > 0){
    return 1
  }else{
    return -1
  }
}
function hhmmss(n){
  hh=n / 60
  mm=n % 60
  return sprintf("%2d:%02d",hh,mm)
}
list mdmlog1.vbs
Set objFS=CreateObject("Scripting.FileSystemObject")
Set objText=objFS.OpenTextFile("$mdmlog1.txt")
myText=objText.ReadAll
MsgBox(myText)
objText.Close
解説
 まずはmdmlog.bat。windowsが吐き出すmodemlog.txt、 実は260KBを超えるあたりで記録が止ってしまうという事実が存在します。 そこで、バックアップをとり(c:\windows\modemlog.bak)、 処理後にはmodemlog.txtを削除します。で、その処理ですが、検索、 置換をsedにて行ってます。modemlog.txt中の「ATDT#」(トーン発振の場合。 パルス発振ならATDP)をアクセス開始時間、「NO CARRIER」を終了時間としました。 何らかのエラーがあって「NO CARRIER」が記録されてなければerrorとします。 そしてアクセス時間を計算する子バッチを組み立てるわけですが、 この計算にはCASE8のlap.batを使います。子バッチ$mdmlog.batを実行すると、 以下のようなmdm.logを出力します。

2000-12-05 01:06:35 2000-12-05 01:23:39 00:17:04

 次にアクセス時間を集計するmodemlog1.bat。集計作業はjgawkにお任せ(笑)。 で、何をやっているのかというと... 興味のある方はスクリプトを追ってくださいね! (自分も何をやらせたのかよく覚えてない(苦笑))。そうそう、 ちなみにアクセスポイントは区域内にあることを前提にしています。 そして結果を$mdmlog1.txtに出力し、mdmlog1.vbsで表示させます。
コメント
 自分で言うのもなんですが、タイムプラスの効果や、 昼夜別の利用時間などが一目で分かるのがいいですね(笑)。欲を言えば、 グラフ表示なんかさせたらもっといいかな?。 そのためにはもっとvbs勉強しなきゃねー(苦笑)。

CASE 9:同じタイムスタンプのファイルのリストを取りたい場合

同じタイムスタンプ(年月日)のファイルをバックアップしようとした時、 このようなtoolが手元に無かったので作ってみました。普段はファイラーのFDで 日付ソートしてマークで済ませていましたが、 あちこちのディレクトリで何回もこの作業をするのも苦痛だなぁ。 さらに最近では1ディレクトリにFDの限界1024を超えるファイルが吹き溜り、 ますます「いや〜んな感じ(苦笑)」ですなぁ...とうい訳です。 あっ、今回のは、一発で異なるディレクトリ間のサーチは出来ません(サーチはできるかもしれないけど、パスの不整合が出るな、たぶん...。ネタが増えたな、これは...(笑))。
dd.bat
【書式】 dd yy[-mm[-dd]] [path ...]

 yy、mm、ddにはそれぞれ年月日(それぞれ2ケタで指定し、ハイフンで区切る)を指定、pathにはサーチディレクトリ、ファイル名を指定出来ます (省略時はカレントディレクトリをサーチ)。
で、実際ファイルのリストはレスポンスファイルに取り出すなどして使用することとなりますが、バッチなのでそのままリダイレクトやパイプ出来ないので、
C:\>command /c dd 98-03 "c:\win95\Temporary Internet Files\cache1\*.htm" >@list
(タイムスタンプが98年3月の、c:\win95\Temporary Internet Files\cache1ディレクトリにある、拡張子htmのファイルのリストを@listにリダイレクト)
や、
C:\>command /c dd 98 *.log *.txt |lha a log98
(タイムスタンプが98年の、カレントディレクトリにある、拡張子log、txtのファイルをlhaで圧縮する)
等、「command /c」を付けて使用することとなります。
list
@echo off
if "%1"=="" goto usage
bu -e -nlen strlen %1
set str=%1
if %len%==2 set str=%1-
if %len%==5 set str=%1-
:loop
shift
if "%1"=="" goto grep
dir /a-d %1 >>$dd
goto loop
:grep
if exist $dd goto seach
dir /a-d >$dd
:seach fgrep " %str%" $dd |cut -b 45- |sed "/^$/d;s/\(.*\)/\"\1\"/"
goto end
:usage
echo usage : dd yy[-mm[-dd]] [path ...]
:end
del $dd
解説
 検索日付(%str%)のレングスをはかり、年(yy)、年月(yy-mm) なら検索日付にハイフンを追加します(yy-、yy-mm-)。 これはfgrepでdirコマンドの日付部分をgrepのターゲットにするためのやや醜い(笑) 処理です。そしてshiftさせながらpathごとに「dir /a-d」で、 ディレクトリを除いたリストを$ddに貯めます。 そしてfgrepさせ、パイプ送り「cut -b 45-」 でロング・ファイルネーム以降を取り出し、 さらにパイプ送りのsedでダブルクォーテーションで括ります。
コメント
 もしかしたら、MSなtoolだけでも出来たかもしれない...(苦笑) でも、まあいいか?
最近、あまりクールなバッチ組んでないなぁ...。 といっても意固地にバッチ野郎続けるのも何か虚しい今日この頃。 wshでもやってみるか?(笑)

CASE 8:経過日時を計りたい場合

masa企画(仮称)第2弾!  経過日時を計るにはどうしたらいいか?と再び話しが振られたので、 CASE4、5を改良して作ってみた訳です。日付関連でいつも厄介なのは「うるう年」で、 今回は、公式の通りに計算しているのでバッチリだと思っていますが... 思わぬバグが潜んでいるかもしれません(苦笑)。
lap.bat
【書式】 lap [-l] yyyy1 m1 d1 h1 m1 s1 yyyy2 m2 d2 h2 m2 s2

 スイッチ「-l」を指定すると「start」「end」「lap」の見出しと日時を表示し、 指定がない時は経過日時のみを表示します。「yyyy1 m1 d1 h1 m1 s1」はstart dateで 西暦(必ず4桁で指定)、月、日、時、分、秒で、「yyyy2 m2 d2 h2 m2 s2」は end dateで同様です。
list
:====================
:lap.bat
:(c)1998 nanai migeru
:====================
@echo off
if "%1"=="-l" set log=1
if "%log%"=="1" shift
:==================
:日付、時間をセット
:==================
set i=0
:setdata
bu calc i++
if "%1"=="" goto usage
if %i%==1 set yy1=%1
if %i%==2 set mm1=%1
if %i%==3 set dd1=%1
if %i%==4 set h1=%1
if %i%==5 set m1=%1
if %i%==6 set s1=%1
if %i%==7 set yy2=%1
if %i%==8 set mm2=%1
if %i%==9 set dd2=%1
if %i%==10 set h2=%1
if %i%==11 set m2=%1
if %i%==12 goto setend
shift
goto setdata
:setend
set s2=%1
bu -nans printf "%%4d-%%02d-%%02d %%02d:%%02d:%%02d %%4d-%%02d-%%02d %%02d:%%02d:%%02d ",%yy1%,%mm1%,%dd1%,%h1%,%m1%,%s1%,%yy2%,%mm2%,%dd2%,%h2%,%m2%,%s2%
:==============
:通年日を求める
:==============
set tunen=0
if %mm1%==1 goto adddd1
if %mm1%==01 goto adddd1
set i=%yy1%
set return=y1uru
goto uru
:y1uru
set i=%mm1%
set return=adddd1
goto tunen
:adddd1
bu -e -nld1 calc %tunen%+%dd1%
set tunen=0
if %mm2%==1 goto adddd2
if %mm2%==01 goto adddd2
set i=%yy2%
set return=y2uru
goto uru
:y2uru
set i=%mm2%
set return=adddd2
goto tunen
:adddd2
bu -e -nld2 calc %tunen%+%dd2%
:==================
:年経過日数を求める
:==================
set lyd=0
if %yy1%==%yy2% goto sub
set i=%yy1%
bu -e -nj calc %yy2%-1
:loop
set return=lyduru
goto uru
:lyduru
bu -e -nlyd calc %lyd%+365+%uru%
if %i%==%j% goto sub
bu calc i++
goto loop
:================
:経過時間を求める
:================
:sub
set lh=0
set lm=0
set ls=0
bu -e -nlday calc %lyd%+%ld2%-%ld1%
::
bu calc s2-s1
if not errorlevel 254 goto subs
bu calc m1++
bu -e -ns2 calc %s2%+60
:subs
bu -e -nls calc %s2%-%s1%
::
bu calc m2-m1
if not errorlevel 254 goto subm
bu calc h1++
bu -e -nm2 calc %m2%+60
:subm
bu -e -nlm calc %m2%-%m1%
::
bu calc h2-h1
if not errorlevel 254 goto subh
bu calc lday--
bu -e -nh2 calc %h2%+24
:subh
bu -e -nlh calc %h2%-%h1%
:========
:結果出力
:========
if not "%log%"=="1" goto nolog
echo start end lap
bu printf "%ans%"
:nolog
if not %lday%==0 bu printf "%lday%日 ",
bu printf "%%02d:%%02d:%%02d\n",%lh%,%lm%,%ls%
goto end
:==================
:うるう年のチェック
:==================
:uru
set uru=0
bu -e -nj1 calc %i% %% 4
bu -e -nj2 calc %i% %% 100
bu -e -nj3 calc %i% %% 400
if %j1%==0 if not %j2%==0 set uru=1
if %j3%==0 set uru=1
goto %return%
:============
:通年日の算出
:============
:tunen
bu calc i--
:tloop
if %i%==1 bu -e -ntunen calc %tunen%+31
if %i%==2 bu -e -ntunen calc %tunen%+28+%uru%
if %i%==3 bu -e -ntunen calc %tunen%+31
if %i%==4 bu -e -ntunen calc %tunen%+30
if %i%==5 bu -e -ntunen calc %tunen%+31
if %i%==6 bu -e -ntunen calc %tunen%+30
if %i%==7 bu -e -ntunen calc %tunen%+31
if %i%==8 bu -e -ntunen calc %tunen%+31
if %i%==9 bu -e -ntunen calc %tunen%+30
if %i%==10 bu -e -ntunen calc %tunen%+31
if %i%==11 bu -e -ntunen calc %tunen%+30
if %i%==12 bu -e -ntunen calc %tunen%+31
bu calc i--
if not %i%==0 goto tloop
goto %return%
:=====
:usage
:=====
echo usage : lap [-l] yyyy1 m1 d1 h1 m1 s1 yyyy2 m2 d2 h2 m2 s2
:end
解説
 コマドラインの引き数がバッチ変数を超えているので、shiftを使って読み込みます。 そして次に通年日(1月1日からの経過日数)を計算します。 うるう年判定を擬似的にサブルーチン化しているところがミソです。 次に年経過日数を計算します。最後にend dateからstart dateを、秒、分、時、 年経過数+通年日の順で引いていきます。
コメント
 今回初めて擬似サブルーチンを組んでみました。この方法は今後も「使える」 手口となりそうです。 ただ、サブルーチンの中からサブルーチンを呼ことが出来ないので、 呼びかたの順番には気を付けなければなりませんが...まあ、 今後の課題という事にしておきましょう。
ちなみにbuの変数の関係で、経過日数が65535日(約179年と5ヶ月あたり) をこえる計算は出来ません。まあ、問題ないとは思いますが...(^^;)。

CASE 7:指定ファイルに通し番号を付けて沢山コピーを作りたい場合

 あるファイルのコピーを、指定した個数分作る。 コピーされたファイルには通し番号を振り、桁を揃える。
 masa企画(仮称)第1弾!(笑) 「cshスクリプトvsバッチ対決」 というのは冗談ですが「バッチで作るとどうなるか?」と話題が振られて、 ここはバッチ野郎としては腕がなる訳です。当初bu、 toolsを使わないpureバッチ版を作ったのですが、 コマンドラインの指定がカッコ悪くmasa氏には不評を買ってしまった(苦笑)ので、 今度はbuを使ってスマートに作り直す訳です。
ncp2.bat
【書式】 ncp2 filename n [re_ext]

 nはコピーする個数、re_extが指定された場合、 コピーされたファイルの拡張子をre_extに付け替えます。 通し番号はファイル名と拡張子の間(filename.txtならfilename0001.txt) に付きます。
list
@echo off
if "%1"=="" goto usage
if "%2"=="" goto usage
bu -e -nlen strlen %2
set i=1
bu -norgext strtokext2 %1
bu -norgfn strtoknode1 %1
:loop
if "%3"=="" goto noreext
bu -nfn printf %orgfn%%%0%len%d.%3,%i%
goto copy
:noreext
bu -nfn printf %orgfn%%%0%len%d%orgext%,%i%
:copy
copy %1 %fn% >nul
if %i%==%2 goto end
bu -e -ni calc i+1
goto loop
:usage
echo usage : ncp2 filename n [re_ext]
:end

解説
 まずn(%2)のレングスをはかり、またfilenameの拡張子を取り出します。 あとはbuのprintf書式設定で桁を揃えコピーします。
制限事項と言えば、常にfilenameのあるディレクトリのみを対象にしているので、 ディレクトリを超えてコピーが出来ない。 まあmasa氏のcshスクリプトもそうなっていたのでまあ、いいか?(笑)
コメント
 このbu版を作る前のpureバッチで初めて足し算するバッチを作ったのですが、 今までにない経験をさせていただきました。まだまだ精進が足りません。

CASE 6:壁紙やサウンドを起動 毎に変えたい場合

 いつも同じ壁紙やファンファーレで起動するのはあきあきです。 私の世代は多かれ少なかれ初期・中期アニメブームを経験している訳で、 当然サウンドの設定には、 キャラクターボイス!というのがデフォルト(自爆)です。 さらに「DOOM」や「Rise of the Triad」「Duke Nukem 3D」にはまった影響もあり、 これらSEも渾然一体となっている状態。
 例えば、WINDOWSの起動には 「なんだか胸がドッキドキするね!」 (TechWinオリジナル:国府田マリ子)」、一般の警告音には 「あんたバカァ?」(アスカ:宮村優子)、 システムエラーには「不自由をやろう...」 (ゲンドウ:立木文彦)、問い合わせにはDOOM2のスパーショットガンのSE、 ゴミ箱にはDUKE3Dの水洗トイレのSE、WINDOWSの終了には 「この次も、サービス、サービスゥ!(はあと)」 (葛城ミサト:三石琴乃)などなど。病気ですね...(自爆)。
media.bat / media_s.bat
 はじめにお好みのWAVファイルを用意して、 割りあてたいメッセージ毎にLHAで圧縮し、ディレクトリ C:\windows\media\ に格納しておきます。壁紙も同様です。 圧縮ファイル名は以下のとおりとします。
種類圧縮ファイル割りあてファイル
windowsの起動winstart.lzh winstart.wav
windowsの終了winend.lzhwinend.wav
システムエラーsyserror.lzhsyserror.wav
メッセージ(警告)meskei.lzhmeskei.wav
メッセージ(情報)mesjou.lzhmesjou.wav
メッセージ(問い合わせ)mestoi.lzhmestoi.wav
一般の警告音ippank.lzhippank.wav
ごみ箱を空にするgomi.lzhgomi.wav
壁紙bmp.lzhbmp.bmp

 とりあえず上記の9種類を対象とするとします。 例えばシステムエラーに割りあてたいWAVファイルなら「syserror.lzh」 に圧縮し格納します。
 次にサウンドのプロパティに、各メッセージに対応した「割りあてファイル」 を設定します。ここでは C:\windows\media\ 以下にファイルがあることとします。存在しないファイルは設定出来ないので、 とりあえずダミーファイルでも作っておいて下さい。壁紙も同様です。
 最後にautoexec.batの最終行に「media.bat」を付け加えます。 これで起動するごとににぎやかな環境があなたをもてなしてくれます(笑)。

list media.bat
c:
cd c:\windows\media
del winstart.wav
del winend.wav
del syserror.wav
del meskei.wav
del mesjou.wav
del mestoi.wav
del ippank.wav
del gomi.wav
del bmp.bmp
bu -e -np CLOCKDAY
for %%a in ( winstart winend syserror meskei mesjou mestoi ippank gomi ) do call media_s %%a wav
call media_s bmp bmp
del $media.bat
del $lst
list media_s.bat
lha l -n %1 |cat -n |tee $lst |wc -l |sed "s/ +\([0-9]+\)/bu \-e \-nrnd random \1\,%%p%%\nbu \-e \-nrnd calc rnd\+1\ngoto %%rnd%%/" >$media.bat
sed "s/ +\([0-9]+\) +\(.*\)/\:\1\nlha e %1 \2\nren \2 %1\.%2\ngoto end/;$s/$/\n:end/" $lst >>$media.bat
call $media

解説
 WINDOWS95側のプロパティをいちいち変更せず、 WAVファイルやBMPファイルの中身を変えるというのが基本原理です。
 それぞれのメッセージの割りあて動作は同じなので、「for in do」 でサブバッチ「media_s.bat」を回します。 実際の割りあてファイルと書庫ファイル名を同じにしてあるのがミソです。
 サブバッッチ「media_s.bat」は、親バッチから割り当てファイル(書庫名も兼ねる) と、割り当てファイルの拡張子を受け取り、 これらを使って実際に割り当て処理を行う子バッチ「$media.bat」を出力、 実行します。処理は以下の通りです。


 こうして出来た「$media.bat」を実行します。動作は、 書庫に格納してあるファイルをbuでランダムで選び、 その数のラベルにgotoしてファイルを解凍、割り当てファイルにリネームします。

コメント
 どうせやるなら、 あきがこないように沢山のファイルを書庫に登録したいところですが、それなりに 「ハードディスクに空きが必要」、「起動に時間が掛かる」等障害も出てきます。 試しに、WAVファイルを話題の「MPEG Layer-3」に圧縮してやったはみましたが、 なぜか鳴ってくれません。家のCPUが非力(i486DX4/100)なせいか?


CASE 5:NIFTYの最終ログインからの経過日数を確認したい場合

 NIFTYのメールボックスは20通しかメールをセーブ出来ないので、 怠慢ネットワーカーは、 最終ログインからの経過日数を計るバッチをAUTOEXEC.BATで呼び出して、 メール着信もれのないように気を付けていました(笑)。 さらにこの頃はジャンクメールの着信が増えたので困ったものです(苦笑)。
 私はwterm(当然DOS版ですね(笑))を常用してますので、 wterm.telファイルを対象にしています。 経過日数によって、3段階の色分けをして表示します。
chk_nif.bat / chk_sub.bat
【書式】 chk_nif wterm.tel

 wterm.telの形式は、

1998-04-01 08:01:58 [00:10:29] 220 円 [xx-xxxx-xxxx] NIFTY-Serve

で、頭から「ログイン開始日付、日時、アクセス時間、料金、アクセスポイントTEL、 ホスト名」になってます。
 chk_nif.batが子バッチchk_sub.batを呼び出します。
list chk_nif.bat
@echo off
fgrep NIF %1 |sort -r |sed "s/^\(....\).\(..\).\(..\).*/chk_sub \1 \2 \3/;q" >$chk_nif.bat
call $chk_nif
del $chk_nif.bat

list chk_sub.bat
bu calc (%1-1992) %% 4
set uru0=0
if errorlevel 1 goto day0set
if errorlevel 0 set uru0=1
:day0set
if %2==01 set day0=%3
if %2==02 bu -e -nday0 calc 31+%3
if %2==03 bu -e -nday0 calc 59+%3+%uru0%
if %2==04 bu -e -nday0 calc 90+%3+%uru0%
if %2==05 bu -e -nday0 calc 120+%3+%uru0%
if %2==06 bu -e -nday0 calc 151+%3+%uru0%
if %2==07 bu -e -nday0 calc 181+%3+%uru0%
if %2==08 bu -e -nday0 calc 212+%3+%uru0%
if %2==09 bu -e -nday0 calc 243+%3+%uru0%
if %2==10 bu -e -nday0 calc 273+%3+%uru0%
if %2==11 bu -e -nday0 calc 304+%3+%uru0%
if %2==12 bu -e -nday0 calc 334+%3+%uru0%
bu -nyy1 printf %%02d,CLOCKYEAR
if %yy1%==98 goto ac19set
if %yy1%==99 goto ac19set
set yy1=20%yy1%
goto uru_set
:ac19set
set yy1=19%yy1%
:uru_set
bu calc (%yy1%-1992) %% 4
set uru1=0
if errorlevel 1 goto day1set
if errorlevel 0 set uru1=1
:day1set
bu -e -nmm1 CLOCKMONTH
bu -e -ndd1 CLOCKDAY
if %mm1%==1 set day1=%dd1%
if %mm1%==2 bu -e -nday1 calc 31+%dd1%
if %mm1%==3 bu -e -nday1 calc 59+%dd1%+%uru1%
if %mm1%==4 bu -e -nday1 calc 90+%dd1%+%uru1%
if %mm1%==5 bu -e -nday1 calc 120+%dd1%+%uru1%
if %mm1%==6 bu -e -nday1 calc 151+%dd1%+%uru1%
if %mm1%==7 bu -e -nday1 calc 181+%dd1%+%uru1%
if %mm1%==8 bu -e -nday1 calc 212+%dd1%+%uru1%
if %mm1%==9 bu -e -nday1 calc 243+%dd1%+%uru1%
if %mm1%==10 bu -e -nday1 calc 273+%dd1%+%uru1%
if %mm1%==11 bu -e -nday1 calc 304+%dd1%+%uru1%
if %mm1%==12 bu -e -nday1 calc 334+%dd1%+%uru1%
bu calc %yy1%-%1
if errorlevel 2 goto the_end
if errorlevel 1 goto add
if errorlevel 0 goto sub
:the_end
echo もうNIFTYやめましょう(苦笑)
goto end
:add
bu -e -nday1 calc 365+%uru0%+%day1%
:sub
bu calc %day1%-%day0%
:日数(1〜254)を指定してください(ここでは15、11、0)
if errorlevel 15 goto red
if errorlevel 11 goto magenta
if errorlevel 0 goto yellow
:red
set color=\e[5;30;41m
goto printf
:magenta
set color=\e[5;30;45m
goto printf
:yellow
set color=\e[5;30;43m
:printf
bu printf "%color%NIFTY最終LOGINより %%d日経過\e[0;37;40m\n",calc %day1%-%day0%
:end
bu keycode hit any key !!

解説
 ようは、現在の日付からLOGファイルにある最終ログイン日付を引けばいいんですが、 手順としては、
@それぞれの日付を、その年の1月1日からの経過日数にしておく。
Aそれぞれの年で引き算し、1年なら現在の日数に1年分の日数を足し、2年以上なら処理はしない(笑)。
B実際に日数を引き算する。
といった感じです。表示する時の色分けですが、 ここでは、経過日数が10日以内なら黄色、15日未満なら紫色、 15日以上なら赤色(DOS/Vのエスケープシーケンス仕様)でメッセージを出力します。
コメント
 なんかgoto分が多くてぜんぜんエレガントでないのが悔しいです(苦笑)。 wterm.telをサンプルとしましたが、 ほかのソフトのLOGもだいたい似たり寄ったりなので流用してください (sedのスクリプトで対応)。とにかく行頭が日付で、対象にしたいホスト名がfgrep (他のgrepでも大丈夫ですが)で拾えればOKです。
 「うるう年」の計算ですが、公式ではありませんのであしからず(苦笑)。 たまたま2000年が例外の「うるう年」だしね。「2100年は?」って、 その頃は生きてないって(苦笑)。

CASE 4:プログラムの実行時間 を計りたい場合

 UNIXにあるtimeコマンドもどきのバッチです。 といっても精度は秒までですけど...。この手のものは、 フリーウェアを探せば結構ありそうですが、手元に無かったので作りました。 バッチ野郎はこういう時に充実感を味わいます。
tc.bat
【書式】 tc exec_file [...]

 実行プログラム(バッチファイルも可)にオプションも指定する場合は8個まで。 実行時間は秒で計算します。結果はtc.logというファイルにアペンド出力します。
list
@echo off
if "%1"=="" goto usage
bu -e -nshh CLOCKHOUR
bu -e -nsmm CLOCKMINUTE
bu -e -nsss CLOCKSECOND
call %1 %2 %3 %4 %5 %6 %7 %8 %9
bu -e -nehh CLOCKHOUR
bu -e -nemm CLOCKMINUTE
bu -e -ness CLOCKSECOND
bu calc %ehh%-%shh%
if errorlevel 254 goto tomorrow
bu -e -nahh calc %ehh%-%shh%
bu -e -namm calc %ahh%*60+%emm%-%smm%
bu -e -nass calc %amm%*60+%ess%-%sss%
goto logout
:tomorrow
bu -e -nahh calc 23-%shh%+%ehh%
bu -e -namm calc %ahh%*60+59-%smm%+%emm%
bu -e -nass calc %amm%*60+60-%sss%+%ess%
:logout
echo run %1 %2 %3 %4 %5 %6 %7 %8 %9>>tc.log
echo start end time >>tc.log
bu printf "%%02d:%%02d:%%02d %%02d:%%02d:%%02d %%5d\n",%shh%,%smm%,%sss%,%ehh%,%emm%,%ess%,%ass% >>tc.log
echo ----------------------- >>tc.log
goto end
:usage
echo usage : tc exec_file [...]
:end
解説
 まず現在の時刻をBUで取り込み、プログラムを実行。終了後再び時刻をBUで取得、 引き算して秒に直しtc.logに出力します。0:00を挟んでの処理にも対応してます。 ただし、計測時間に制限があります。18時間12分15秒を超える計測は出来ません。
コメント
 長時間かかるプログラムのことを考えていなかったので(苦笑)、 計測時間を秒で出力するという仕様に安易に決めたため、 BUで扱える最大数65536の制限に思いっきり引っ掛かってしまいました。

CASE 3:LZHファイル以外もMIELする場合

 言わずと知れた定盤pager、A.Idei/Paci氏作「MIEL」ですが、 いつもお世話になっております。着々と機能アップにより、 拡張アーカイブ機能でLZH以外の圧縮ファイルもMIEL出来るようになりました。その際、 テンポラリに展開したmieltmp.000は、「ESCキー」 でメニューを出した時に削除されます。私は普段「Qキー」で終了する習慣があり、 このメニュー表示には少々ストレスがあります。 そこで独自に圧縮ファイルを展開してMIELし、 MIEL終了後後始末するバッチがあれば便利だなぁと言う訳です。 そして、このバッチをこれまた定盤ファイラー、A.Idei氏作「FD」 のユーザーコマンドに登録して運用すれば完璧です。
xmiel.bat
【書式】 xmiel filename

 filenameの拡張子、zip、tar、tgz等を見分けて各arcutを起動しテンポラリ (c:\ztmpを指定)に展開、それ以外はMIELに直接送ります。 今回は、解凍DLLをコマンドラインから動かせる、吉岡恒夫氏作「unpack.exe」 (tar32.exeとリネームしています)を使い、bz2にも備えました。
list
set arcut=
set ztmp=c:\ztmp
bu -nSUF strtokext %2
rem s0に拡張子、s2にarcut(オプションが必要ならオプションも指定)
rem if %suf%==s0 set arcut=s2
if %suf%==LZH set arcut=lha e -xr
if %suf%==ZIP set arcut=unzip
if %suf%==TAR set arcut=tar xvf
if %suf%==TAZ set arcut=tar xvf
if %suf%==TGZ set arcut=tar xvf
if %suf%==GZ set arcut=gzip -d
if %suf%==BZ2 set arcut=tar32 xvf
if %suf%==LZZ set arcut=gzip -d
if %suf%==GZ copy %2 c:\ztmp
if %suf%==LZZ copy %2 c:\ztmp
if "%arcut%"=="" goto miel
bu pushd %ztmp%
if %suf%==GZ goto gzip
if %suf%==LZZ goto gzip
bu -e -nlen strlen %pushdtmp%
if %len%==3 %arcut% %pushdtmp%%2 >nul
if not %len%==3 %arcut% %pushdtmp%\%2 >nul
goto gomiel
:gzip
%arcut% %2
if %suf%==LZZ ren *.lz *.lzh
:gomiel
miel
rm -rf %ztmp%\*
goto end
:miel
miel %2
:end

解説
 まずBUでMIELしたいファイルの拡張子を取り込み、 if文で拡張子ごとのarcutを選択させ環境変数arcutに解凍コマンドをセットします。 ここで環境変数arcutがセットされない場合はそのままMIELに渡します。 次に、テンポラリ(c:\ztmp)にpush、カレントディレクトリを移動します。 環境変数pushdtmpを利用してカレントディレクトリ(c:\ztmp) に解凍する訳です。あとはMIELに渡します。 MIEL終了後、テンポラリ中のファイルを削除し、BUでpopして終了です。
コメント
 まず「lzz」について。これは「LHAで無圧縮格納(-z オプション)し、gzipで圧縮」というやつです(^^;)。素直にtgzにすればいいのですが、tarするとゴミ(笑) がつく分若干サイズが大きくなります。少しでも小さく圧縮するための苦肉の作... そう、メインマシンがPC-9801VX21で、HDDのクラスタサイズが1024byte(^^;) の時代の話です(苦笑)。今の大容量時代では無意味な行為なのでしょうか?
 他のアーカイバはすんなりいったのに、gzipだけはうまく行きません。 pushしても、もとのディレクトリに直接作用してしまいます。そこで、「gz」と「lzz」 のときはテンポラリに圧縮ファイルをコピーさせました。さらに「lzz」 はgzipで展開すると拡張子が「lz」になってしまうので"h"を補いました。 でもMIELは「lz」のままでもちゃんと中身を確認してくれるので、 わざわざそうする必要も無かったのですが...。
 今回悩まされたのが環境変数pushdtmp。カレントディレクトリの位置によって、 動いたり動かなかったりするバグに見舞われました。 環境変数pushdtmpをトレースしたところ、「c:\」「c:\tansu」というように「\」 が付く場合と付かない場合があったのです。そのため、 pushdtmpのレングスを計って対応させました。STRTOK*したほうがよかったかな?。

CASE 2:気の利いた日付の確認がしたい場合。(joke)

 case1の作成中に出来たジョークバッチ。ちゃんと日付が戻っているか、 boot時に画面一杯に日付が表示されたら確認しやすいだろうと思って、 バナープログラムなど探している途中、嶋田 大貴氏作「ルパン for Windows」 に出会いました。 オプションに表示したい文字列を指定できるのでここに日付を指定すれば、 なんともかっこいい(笑)日付の確認が出来る訳です。
lpndate.bat
 日付などのデータをすべてBUから取得するlist1と、アスキーのsoftware toolsの 「ktime」で一発getするlist2です。「ルパン for Windows」lupin.exeは、 c:\win95\ut\lupin\lupin.exeにあるとします。
list1
bu -nyy0 printf %%02d ,CLOCKYEAR
echo %yy0%
set yy1=20
if %yy0%==98 set yy1=19
if %yy0%==99 set yy1=19
bu -e -nm CLOCKMONTH
bu -e -ndd CLOCKDAY
bu -e -nwk0 CLOCKWEEK
if %wk0%==0 set wk1=日
if %wk0%==1 set wk1=月
if %wk0%==2 set wk1=火
if %wk0%==3 set wk1=水
if %wk0%==4 set wk1=木
if %wk0%==5 set wk1=金
if %wk0%==6 set wk1=土
set ampm=午前
bu -e CLOCKHOUR
if errorlevel 12 set ampm=午後
bu -e -nhh CLOCKHOUR
if %ampm%==午後 bu -e -nhh calc %hh%-12
bu -e -nmm CLOCKMINUTE
bu -e -nss CLOCKSECOND
bu -e -ndate DSPDATE
echo %yy1%%yy0%年 %m%月 %dd%日 (%wk1%) %ampm% %hh%時 %mm%分 %ss%秒 |sed "y/0123456789/0123456789/;s/^/c:\\win95\\ut\\lupin\\lupin /" >$lpndate.bat
call $lpndate
del $lpndate.bat
list2
ktime |sed "s/^/c:\\win95\\ut\\lupin\\lupin /" >$lpndate.bat
call $lpndate
del $lpndate.bat

解説
 まずlist1。BUで日付などのデータを環境変数に取得します。なお、 LUPIN.EXEには全角文字がよいそうなので (True Typeフォントで見栄えを良くするためにもね...) 環境変数の値を全角文字に変換しなければいけません。 ダラダラとif文を使って変換する強引な力技でもいいんですが、 ここはsedを使って変換し、 さらに子バッチからLUPIN.EXEを起動する手順で行く事にします。
 BUでは西暦は下2桁しかgetできないので、まず頭2桁を20としておいて下2桁が98、 99なら頭2桁を19に直すようにif文をかませました。また午前、 午後も表示するためここも同様なif文で処理します。 データが揃ったところでecho文でパイプにしてsedに送ります。 yコマンドで半角数字を全角に置換します。そして頭に実行ファイルLUPINを置いて (スクリプト中なので\は\\とエスケープしてます) 子バッチ$lpndate.batを作ります。call文で子バッチ$lpndate.batを実行し、 最後に子バッチを削除して後片付けします。
 list2は「ktime」で一気に文字列をget出来るので、 後はsedで子バッチの形にするだけなので超スッキリ!
コメント
 環境変数に入っている文字を全角に変換出来るtoolがあれば、 子バッチを持ち出さなくても出来るのにね?
 このバッチの使用期限は2097年12月31日までです。 2098年になると西暦が100年戻ってしまいます(笑)。はたしてその時まで、 このバッチが動いている...訳はないねぇ(苦笑)。

CASE 1:正味期限切れのソフト(笑)を試食し続けたい場合。

 何月何日まで、と正味期限のあるソフトがありますが、 リスクを承知で試食し続けたいという場合はどうしたらいいのでしょう? 自力でクラックするほどのスキルが無い場合、 一番簡単なのは日付を変更することですね。 でも手動でいちいち日付を変更するのは面倒です。 また戻し忘れて通信ソフトのLOGファイルが狂ってしまったりするとなお厄介ですね。 (体験済み(^^;))そこで正味期限切れソフトの起動前に、 日付を正味期限内に変更し、 終了後にもとに戻すバッチファイルがあると便利だなぁと思う訳です。
nolim.bat
【書式】 nolim year month filename [...]

 実行ファイルが、C:\Program Files\Sample\program.exe(オプションに"-o lst.txt" を付ける)、正味期限を1998年2月28日までとすると 「nolim 1998 2 "C:\Program Files\Sample\program.exe" -o lst.txt」とこんな感じ。 バッチ変数を使っているのでfilename以降に指定できる文字列は7つまで。 shift使えばよかったかな?
 list1はdosの内部コマンドとsedで子バッチを召喚する方法(機能制限あり。後述)、 list2は素直にBUを使ったもの。
list1
echo. |date |sed "1s/.*\(....\)\-\(..\)\-\(..\).*/date %1-%2-\3\nstart \/w %%1\ndate \1-\2-\3\n/;q" >$nolim.bat
call $nolim %3 %4 %5 %6 %7 %8 %9
del $nolim.bat
list2
bu -e -nyy CLOCKYEAR
bu -e -nmm CLOCKMONTH
bu -e -ndd CLOCKDAY
bu -e -nhh1 CLOCKHOUR
if %yy%==98 goto 19
if %yy%==99 goto 19
bu -e -nyy calc 2000+%yy%
goto dset
:19
if %yy%==98 set yy=1998
if %yy%==99 set yy=1999
:dset
date %1-%2-%dd%
start /w %3 %4 %5 %6 %7 %8 %9
bu -e -nhh2 CLOCKHOUR
bu calc %hh2%-%hh1%
if errorlevel 254 goto adddd
goto dreset
:adddd
bu -e -ndd calc %dd%+1
if %mm%==2 goto 2
if %dd%==32 goto 32
if %dd%==31 goto 31
goto dreset
:31
if %mm%==1 goto dreset
if %mm%==3 goto dreset
if %mm%==5 goto dreset
if %mm%==7 goto dreset
if %mm%==8 goto dreset
if %mm%==10 goto dreset
if %mm%==12 goto dreset
bu -e -nmm calc %mm%+1
set dd=1
goto dreset
:32
bu -e -nmm calc %mm%+1
if %mm%==13 goto addyy
set dd=1
goto dreset
:addyy
bu -e -nyy calc %yy%+1
set mm=1
set dd=1
goto dreset
:2
set uru=1
bu calc (%yy%-1992)%%4
if errorlevel 1 set uru=0
if %dd%==30 if %uru%==1 goto addmm
if %dd%==29 if %uru%==1 goto dreset
if %dd%==29 if %uru%==0 goto addmm
goto dreset
:addmm
set mm=3
set dd=1
:dreset
date %yy%-%mm%-%dd%
解説
 list1では、一発で日付データを取り込めないので、 sedの活躍によって子バッチで実際の処理を行う。 filenameも子バッチに埋めこみたいが、「\」や「.」 などはsedスクリプト中なのでエスケープしなければならず、 これを回避するためとりあえず子バッチの「%1(ややこしいですが、バッチ中なので 「%%1」とさらにエスケープしています)」にしておいて、 子バッチ実行時にfilenameを渡します。子バッチ上で正味期限内の年、月 (サンプルでは1998と2)にセットし、satrt /w でターゲットファイルを実行。 実行後もとの年月日にセットして終了、親バッチに戻り子バッチを後始末する。
 list2はBUで日付データを読み込み、正味期限内の日付をセットし実行。 終了後BUを使い、AM0:00を挟んだ場合の日付修正処理を行う。
コメント
 list1の注意点は、日付が変わる時間(AM 0:00) をまたいで使うとちゃんともとに戻れないという事。
 list2ではBUを使い、24時間を超えて使用してなければきちんと戻る。また このバッチの正味期限は2097年まで(苦笑)。
 ソフトによっては動作中にも日付チェックが行われているかもしれないので、 念のためstartコマンドに /w オプションを付けて ソフト終了後までバッチの進行を止めてみた。

 実際には年だけを変更すれば大丈夫だと思うが、「**年*月中のみ」 なんてのがあるかもしれないので、より汎用的に月も指定させてみた。 運用としてはnolim.batショートカットのコマンドラインに、 ソフト毎の設定をして使い分ければ便利。

このページの履歴

2000/12/11 1999/2/4 1998/6/16 1998/5/7 1998/4/30
GOTO TOP

All Rights Reserved. Copyright (C)1998-2000 Nanai Migeru
nanai@geocities.com


このホームページのホストは です。 無料ホームページをどうぞ!