[WSH] Windowsのコマンドプロンプトで正規表現を使って、文字列置換

2017年2月20日月曜日

C# JavaScript Windows WSH

ファイルや標準出力の内容を文字列置換したいなんてことはよくあるよね。
こんなときUnixだと、sedやawkを使うところだけど、Windowsのコマンドプロンプトでは該当するコマンドが用意されていない。
バッチに変数の文字列置換をする機能はあることはあるけど、バッチでループをするのもなんだし、正規表現も使えない。

もちろん、PowerShellを使うって選択肢もあるけど、PowerShellはPowerShellの中に閉じた世界で、既存のコマンドとの連携がしにくいってのがある。

で、Windowsに標準搭載されている機能でなんとかしようとすると、WSHでスクリプトを組んでしまうのが一番簡単だと思う。

WSHで正規表現置換

replace.js
// cscript //nologo replace.js

var flags = (WScript.Arguments.length > 2 ? WScript.Arguments(2) : '');
var re = new RegExp(WScript.Arguments(0), flags);

while (!WScript.StdIn.AtEndOfStream) {
  var str = WScript.StdIn.ReadLine();
  WScript.StdOut.WriteLine(str.replace(re, WScript.Arguments(1)));
}

replace.jsは引数を3つ取る。最初の2つは必須で3つ目はオプション。
1つ目はマッチング用の正規表現文字列、2つ目は置換後の文字列、3つ目はRegExpに渡すオプション。
正規表現やオプションで実際に使えるものは以下参照で。

JScript ランゲージ リファレンス Regular Expression オブジェクト

これで、標準入力を正規表現を使って置換して、標準出力に出すことができる。

WSHだけで、やりたいことを全部書いてしまうのも一つの手だけど、上記のような汎用的なスクリプトを作って、他のコマンドと組み合わせる方がなにかと便利だよね。

これこそがUnixの精神であった。
おっと、Windowsの話を続けよう。

コマンドと組み合わせる

これを使って、Program Filesの中にあるフォルダのリストに番号を付けて、表示してみよう。
基本的なアイデアとしては dir | findstr | replace.js で。

findstrは /n オプションで行番号を出力してくれるけど、そのままでは表示は
1:
になるので、これを
[1]
に変えてみよう。

dirlist.cmd
@echo off

dir /ad /b "C:\Program Files" | ^
findstr /n /r ".*" | ^
cscript //nologo replace.js "([^:]*):" "[$1] "
※ちなみにWindowsのコマンドプロンプトの行継続文字は ^ だった。ちょっと意外。