日々常々

ふつうのプログラマがあたりまえにしたいこと。

テキストファイルを分割するバッチ

単純で力技で何とかなる作業ってのは山ほどあります。実際に物質の移動を伴ったりする場合は本当に力技で作業しなくてはいけないでしょうけど、コンピュータ上で行う作業なのに力技で行うのはあまりにも無駄が多いと言えます。
今回のお題は、大量のテキストファイルをいくつかのファイルに分割する作業。実際に直面したのは、SQLを叩いて戻ってきたテキストをCSV形式の個別ファイルに分割したいと言う事。DBからデータを抜き出したい時にダンプが使えない環境において、Telnetでログ保存したり、ORACLEならSQL*plusでspoolした結果が1ファイルに保存されていて、それを分割してLoaderや外部表で取り込みたいってやつでした。
不要文字の削除等の作業は適当なエディタの正規表現を使った置換であっさり片付くのですが、ファイルに分割するとなると結構な作業になりまして。範囲指定して別ファイルに保存なんてやってると、10や20ならともかく100を超えると面倒だし、1000ともなると日が暮れます。手作業だとミスも考えられます。やる作業は単純なので何かしらのプログラムでいけそうなもの、とはいえ作業端末にはPerlJavaも入っておらず。この2言語を挙げているのは私がさくっと扱えるからと言うだけの理由です。
そんなこんなでWindows端末だったのでバッチにしました。

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION

SET TARGETFILE=読み込むファイル
SET FILENAME=ダミー

FOR /F "tokens=1,2 delims==" %%i IN (%TARGETFILE%) DO ^
IF "%%i" == "file" (SET FILENAME=%%j) ELSE (ECHO %%i >> !FILENAME!)

ENDLOCAL

ファイルの途中にファイル名指定行(「file=ファイル名」の行)があれば、その行以降を次のファイル名指定行まで、指定されたファイル名のファイルに出力します。デリミタには「=」を使っているので、出力結果に「=」があったらうまく動きません。そういう場合は別の文字を使うか、デリミタによる分割を考慮した出力にしてください。

ちょっと詰まったのが、環境変数がFORの実行中に上書きできず、実行前に展開されてしまうこと。知ってる人には当然の話なのかもしれませんが、面食らいました。ここでは出力ファイル名の{FILENAME}を書き換えようとしたのですが、実行前に全てに「ダミー」が設定されるため、ファイルの内容が全部ダミーファイルに出力されてしまいました。
解決のために使っているのが、SETLOCALのENABLEDELAYEDEXPANSIONです。遅延環境変数の展開とか言うらしく、これのおかげで環境変数の途中変更が可能になっています。