Tips【WSH】VBSCRIPTでコンソール出力(wscriptとcscriptで切り替え)
WSHではWScript.echoというメソッドでコンソール出力がおこなえるが
Cscript(コンソール)の場合はコンソールに出力、WScriptの場合はメッセージダイアログに出力という余計なお節介便利な実装となっている。
またコンソール出力する方法としてWScript.StdOut.WriteLine というメソッドもあるのだが、これはcscript専用で、WScriptで実行すると「ハンドルが無効です」というエラーとなってしまう。
デバッグ目的や処理の経過を出力しようとした場合WScript.echoの度にダイアログが出力されるのはよろしくないので何らかの方法を考えましょう。というのがこのエントリ
- CScriptの時だけコンソールに出力してWScriptの時は出力しない
- CScriptの時だけコンソールに出力してWScriptの時はファイルに出力する
- CScriptの時もWScriptの時もファイルに出力する
3は別の機会のネタに取っておくとして1について考察
方法としては2通り(もっとあるかも)
- とりあえず出力してみてエラーなら出力しない
- CScriptかWScriptかを判断して出力するしないを切り替える
とりあえず出力してみてエラーはスキップ
On Error Resume Nextでエラースキップできるので
①
Sub DebugPrint(text) On Error Resume Next WScript.StdOut.WriteLine text End Sub
うん。シンプルですね。
CScriptかWScriptかを判断して出力するしないを切り替える
最初にCScriptかどうかを判断してIf文で出力するかしないかを切り替える。
自分自身はCScriptかWScriptかは、WScript.FullNameでわかるらしいので
②
CSCRIPT_EXE="cscript.exe" If LCase(Right(WScript.FullName, Len(CSCRIPT_EXE))) = CSCRIPT_EXE Then isCSCRIPT = True Else isCSCRIPT = False End If Sub DebugPrint(text) If isCSCRIPT Then WScript.StdOut.WriteLine text End If End Sub
ってな具合に判断する。
なんか関数に収まりきらないでハンドリングが悪いので、毎回判断するオーバーヘッドを顧みず毎回CScriptかどうかを判断すると
③
Sub DebugPrint(text) CSCRIPT_EXE="cscript.exe" If LCase(Right(WScript.FullName, Len(CSCRIPT_EXE))) = CSCRIPT_EXE Then WScript.StdOut.WriteLine text End If End Sub
で、どれがいいのか
性能
10万回ほどループで回して時間を測定してみましょう。
こんな感じのテストプログラム
startTime = Timer FOR i=0 To 1000000 DebugPrint "bbb" Next WScript.echo Timer - startTime
マシンスペックやらなんやらで変わるとは思いますが
WScriptで実行
1回目 | 2回目 | 3回目 | 平均 | 一回当たり(ns) | |
①エラースキップ | 3.292969 | 3.292969 | 3.243906 | 3.276615 | 33 |
②判断 | 0.296875 | 0.273438 | 0.254906 | 0.275073 | 3 |
③毎回判断 | 2.625 | 1.703125 | 1.574219 | 1.967448 | 20 |
CScriptで実行
1回目 | 2回目 | 3回目 | 平均 | 一回当たり(ns) | |
①エラースキップ | 11.15234 | 10.88281 | 10.82031 | 10.95182 | 110 |
②判断 | 12.45313 | 10.125 | 10.30469 | 10.96094 | 110 |
③毎回判断 | 11.88672 | 12.73828 | 12.25391 | 12.29297 | 123 |
※これは実際に文字列を出力している時間も含まれる
WScriptの場合はエラーが発生するため、そのオーバーヘッドが出てくる感じですかね。CScriptの場合は差がほとんどなくなって余分な処理が入っている③が一番時間がかかる。
どれも1回あたりの時間は大した違いがないのでどの方法でもいんでないかい?
ハンドリング
呼び出し側からの使いよさは①=③>②、初期処理で入れといたりグローバル変数になる②はいまいち
拡張性
CScriptの時はコンソールに出して、WScriptの時はファイルに出すとかするって事をしたくなった時とか、②=③>①
結論
③を採用!
Sub DebugPrint(text) CSCRIPT_EXE="cscript.exe" If LCase(Right(WScript.FullName, Len(CSCRIPT_EXE))) = CSCRIPT_EXE Then WScript.StdOut.WriteLine text End If End Sub