こんにちは。現場の最前線でコードと格闘している皆さん、お疲れ様です。
今日は、VBScriptとWindows Script Host (WSH) を操る上で、多くのエンジニアが一度は膝を屈する「コマンドライン引数の特殊文字」という深淵についてお話ししましょう。
「バッチファイルから引数を渡したのに、なぜか途中で文字が消える」「`&` を入れたらエラーが出る」。そんな経験はありませんか?
これはVBScriptのバグではありません。コマンドプロンプト(cmd.exe)という「翻訳機」が、スクリプトにバトンを渡す前に勝手に引数を解釈してしまうことが原因です。この「翻訳のズレ」を完全に掌握し、どんな文字列も正確に受け取るための知見を授けます。
—
1. なぜ「引数」は裏切るのか?
コマンドプロンプトにおいて、`&`, `|`, `<`, `>`, `^` といった記号は、「コマンドの制御命令」として定義されています。
例えば、`cscript.exe script.vbs arg1&arg2` と打ったとき、コマンドプロンプトは以下のように解釈します。
1. `cscript.exe script.vbs arg1` を実行する。
2. その後、`arg2` という別のコマンドを実行しようとする。
結果、VBScript側は「arg1」しか受け取れず、想定外の挙動やエラーが発生します。これが「パース崩れ」の正体です。
—
2. 鋼鉄の引数解釈エンジンを構築する
この問題を解決する唯一無二の正攻法は、「エスケープされた引数を、VBScript側で再構築する」ことです。
バッチファイル側で引数を渡す際、あらかじめ特殊文字を「無害な文字」に置換しておき、VBScript側で元に戻すというアプローチを採ります。以下が、実戦でそのまま使える「堅牢なパースロジック」です。
構築ロジック:エスケープ&復元エンジン
‘ 引数から特殊文字を正しく復元するクラス
Class ArgumentParser
‘ 特殊文字を一時的に退避させるための独自コード
‘ 現場では、まず出現しない文字列の組み合わせを選ぶのがコツです
Private Const ESC_AMP = “{AMPERSAND}”
Private Const ESC_PIPE = “{PIPE}”
Public Function GetNormalizedArgs()
Dim objArgs, i
Set objArgs = WScript.Arguments
Dim normalizedList()
ReDim normalizedList(objArgs.Count – 1)
For i = 0 To objArgs.Count – 1
Dim strArg
strArg = objArgs(i)
‘ 逆変換:退避コードを元の記号に戻す
strArg = Replace(strArg, ESC_AMP, “&”)
strArg = Replace(strArg, ESC_PIPE, “|”)
normalizedList(i) = strArg
Next
GetNormalizedArgs = normalizedList
End Function
End Class
‘ — 実践的な利用例 —
Dim parser, args, arg
Set parser = New ArgumentParser
args = parser.GetNormalizedArgs()
For Each arg In args
WScript.Echo “受け取った引数: ” & arg
Next
—
3. バッチファイル側での「前処理」が鍵
スクリプトだけ完璧でも、入り口が崩れていては意味がありません。呼び出し側のバッチファイルでは、以下のように記号を「無害化」して送り出します。
@echo off
:: 特殊文字をエスケープコードに置換してVBSに渡す
setlocal enabledelayedexpansion
set “rawArg=A&B|C”
set “escapedArg=%rawArg:&= {AMPERSAND}%”
set “escapedArg=%escapedArg:|= {PIPE}%”
cscript //nologo script.vbs “%escapedArg%”
—
4. 現場のプロが教える「陥りやすい罠」
- 「クォーテーション」の呪縛:
引数を `”` で囲めば大丈夫、と思っていませんか?実は、ダブルクォーテーション自体がコマンドプロンプトのパースルールに影響を与える場合があります。パスに空白が含まれるときは必ず囲むべきですが、それだけでは特殊文字は防げません。上記の置換法と併用するのが鉄則です。
- WScript.Arguments.Countを過信するな:
引数が空のときにループを回そうとすると、メモリ領域の参照でエラーになることがあります。必ず `If WScript.Arguments.Count > 0 Then` でガードを固めるのが、堅牢なコードへの第一歩です。
- パフォーマンスの重み:
VBScriptはインタプリタ言語です。数万件の引数を扱うような処理には向きません。もし引数が膨大になる場合は、引数を直接渡すのではなく、一時ファイル(JSONやテキスト)に書き出し、それを読み込む設計へ切り替える勇気を持ってください。
—
まとめ:自動化の先にあるもの
いかがでしたか?特殊文字のエスケープ処理は、一見すると地味で面倒な作業です。しかし、この「外部からの入力を信用しない」という姿勢こそが、バグのない堅牢な自動化システムを構築するエンジニアの矜持です。
ここをクリアすれば、あなたのVBScriptは、どんな環境下でも安定して動作する「信頼できる相棒」になります。ぜひ現場のコードで試してみてください。
分からないことがあれば、いつでもまた聞きに来てくださいね。技術の深淵を一緒に歩んでいきましょう!
