【入門編】【ストリームパイプ処理】CScript 実行における WScript.StdIn 逐次読み込みと超高速テキストフィルタリング – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

こんにちは!VBScriptの世界へようこそ。
マクロの記録や、決まったファイルをポチポチと手動で処理する作業から一歩抜け出して、「本物の自動化」を手に入れたいと思っていませんか?

今回は、VBScriptとWindows Script Host(WSH)が持つ隠れたポテンシャル、「ストリームパイプ処理」の世界にご案内します。
ここをクリアすれば、あなたも単なるスクリプトの利用者から、システムを裏から操るエンジニアへとステップアップできますよ。しっかりついてきてくださいね!

1. なぜ「一括読み込み」ではダメなのか?(巨大データの罠)

業務で数万行、数百メガバイトもある巨大なログファイルやCSVデータを処理することはありませんか?

初心者がやりがちなのが、ファイルを丸ごとメモリに読み込んでから処理する方法です。
小さなファイルならこれでも動きますが、巨大なデータになるとどうなるでしょうか?

  • パソコンのメモリがパンクする
  • 処理が極端に重くなり、最悪の場合はフリーズする

ここで登場するのが、「ストリームパイプ処理」です。
水道の蛇口をひねると、必要な分だけ水が流れてきますよね。あれと同じです。データを丸ごと抱え込まず、「1行ずつ受け取って、処理して、捨てる(次の行へ行く)」を繰り返すことで、メモリ消費量を極限まで抑え、超高速なテキストフィルタリングを実現します。

2. VBScriptにおける「パイプライン」の仕組み

Windowsのコマンドプロンプト(またはPowerShell)では、`|`(パイプ)記号を使って、あるコマンドの出力を別のコマンドの入力に渡すことができます。

type huge_data.csv | cscript //nologo filter.vbs

このとき、`filter.vbs` 側で標準入力(`WScript.StdIn`)をどう受け取るかが勝負の分かれ道になります。

WScript.StdIn の2つの顔

1. `ReadAll` メソッド: 全データを一気にメモリへ読み込む(禁忌:巨大データには使わない!
2. `AtEndOfStream` と `ReadLine`: 1行ずつストリームとして読み進める(今回マスターする王道!

3. 実践!超高速・低メモリのテキストフィルタリングスクリプト

それでは、実際に現場でそのまま使える実用的なコードを見ていきましょう。
今回は、標準入力から流れてくるデータのうち、特定のキーワード(例: `ERROR`)を含む行だけを抽出し、さらに行番号をつけて出力するフィルタースクリプトを作成します。

デスクトップなどに `filter.vbs` という名前で保存してください。

‘ ==============================================================================
‘ スクリプト名: filter.vbs
‘ 概要: 標準入力から受け取ったデータを1行ずつストリーム処理し、
‘ 指定したキーワードを含む行だけを抽出して出力する
‘ 実行方法: type sample.log | cscript //nologo filter.vbs
‘ ==============================================================================

Option Explicit

Dim objStdIn, objStdOut
Dim strLine, lngLineCount, strKeyword
Dim matchCount

‘ 標準入力と標準出力のオブジェクトを取得
Set objStdIn = WScript.StdIn
Set objStdOut = WScript.StdOut

‘ 検索するキーワード(ここでは例として “ERROR” を指定)
strKeyword = “ERROR”

‘ 行カウンターとマッチカウンターの初期化
lngLineCount = 0
matchCount = 0

‘ 【核心】ストリームの終端に達するまで、1行ずつメモリに優しく読み込む
Do While Not objStdIn.AtEndOfStream
strLine = objStdIn.ReadLine
lngLineCount = lngLineCount + 1

‘ キーワードが含まれているか判定(大文字小文字を区別しない場合は InStr を活用)
If InStr(1, strLine, strKeyword, vbTextCompare) > 0 Then
matchCount = matchCount + 1
‘ 標準出力へ書き出す
objStdOut.WriteLine “[” & lngLineCount & “行目] ” & strLine
End If
Loop

‘ 処理結果をエラー出力(StdErr)へ流す(標準出力と混ざらないようにするため)
WScript.StdErr.WriteLine “———————————-”
WScript.StdErr.WriteLine “処理完了: 全 ” & lngLineCount & ” 行中、” & matchCount & ” 行がマッチしました。”

‘ オブジェクトの解放(メモリ管理の基本)
Set objStdIn = Nothing
Set objStdOut = Nothing

コードのここがポイント!

  • `Option Explicit`: 変数の宣言を強制するお約束です。タイポによるバグを未然に防ぐプロの嗜みですね。
  • `Do While Not objStdIn.AtEndOfStream`: 「データの終わりが来るまでループする」という、ストリーム処理の基本形です。ファイルサイズが何ギガバイトあっても、メモリを圧迫しません。
  • `WScript.StdErr`: 処理件数などのメッセージは、通常の出力(`StdOut`)に混ぜると後続のパイプ処理の邪魔になるため、エラー出力ストリームに逃がすのが美しい設計です。

4. 陥りやすい罠とエラー回避の知恵

初心者がこのストリーム処理に挑戦したとき、必ずと言っていいほどハマる「罠」がいくつかあります。ここで先回りしてクリアしておきましょう。

罠その1: 「WScript.Echo」を使ってしまう

VBScriptの入門書によく出てくる `WScript.Echo`。あれを使うと、実行するたびに余計な「ダイアログボックス」がポップアップしてしまいます。コマンドラインのパイプ処理でダイアログが出たら、自動化はそこでお手上げになってしまいますよね。
対策: コマンドラインからの出力には必ず `WScript.StdOut.WriteLine` を使いましょう。

罠その2: `CScript` ではなく `WScript` で実行してしまう

Windowsには、GUI用の `wscript.exe` と、CUI(コマンドプロンプト)用の `cscript.exe` の2つが存在します。標準入力や標準出力を扱うパイプ処理は、必ず `cscript` で実行しなければエラーになります。
対策: 実行時は面倒でも必ず `cscript //nologo script.vbs` のように明示的に呼び出してください(`//nologo` をつけると余計なバージョン情報が表示されず、出力結果が綺麗になります)。

5. まとめ

お疲れ様でした!今回は、VBScriptを使った「WScript.StdIn 逐次読み込みとストリームパイプ処理」について解説しました。

  • 巨大データは一括読み込みせず、`AtEndOfStream` と `ReadLine` で1行ずつ処理する。
  • 出力には `WScript.StdOut.WriteLine` を使い、GUIのダイアログを排除する。
  • 実行は必ず `cscript //nologo` を経由する。

ここをクリアできたあなたは、もう初心者マークを卒業です。VBScriptの地味なシンパシーの裏にある、強靭なOS連携能力を感じられたのではないでしょうか。

日々のバッチ処理やログ解析の自動化に、ぜひこのテクニックを取り入れてみてください。あなたの業務が劇的に高速化することを保証します。
それでは、次のステップでお会いしましょう!

タイトルとURLをコピーしました