バッチの小ネタ1
バッチ処理で調べた&作った内容を書いていく。
要件定義
・フォルダのPNGファイル名を見ていき、"*1.png"の"1.png"を削除し、"*.dat"という名前のファイルを作成していく(設定ファイル)
→別のバッチとして作ったが、下記と似たような内容になったので、今回は省略
・そのファイルパスリストを一覧にしてテキストへ出力
・5行毎に"# 005""#010"…といった文字列の行を挟む
・バッチはPNGファイルが入っているフォルダで実行する
・ファイルの順番はフォルダの物と同じでOK(ABC順)
1-1.現在のフォルダ名のみを取り出す
SET FOLDER_NAME=
SET FilePath=%~p0
SET FilePath=%FilePath:~0,-1%
FOR /F "DELIMS=" %%A IN ("%FilePath%") DO SET FOLDER_NAME=%%~nxA
FOLDER_NAMEにフォルダ名(例:c:\program\test でバッチを動かした場合、test)が入る。
解説:
%~p0 引数%0(=バッチファイル自身)のフォルダパスを得る(フルパス)
%~変数名 「""」ダブルクォーテーションを除く
%p変数名 最後のファイル名を除く
%変数:~m,-n% 最初からm文字目から、最後から数えてn文字目までを取り出す("-"は「最後から数える」)~m,n ~-m,-nなどバリエーションあり。
FOR /F ”DELIMS=" IN ("文字列") DO 文字列を分割して、1個ずつDOのしょ
DELIMS 区切り文字。"\"を入れるが入れなくても良いようだ
2行目で自分のフォルダパスをフルで取得
3行目で最後の"\"マークを削除
4行目は"\"で分解して、FOLDER_NAMEに上書きしていく
最終的に最後のフォルダ名が残るという寸法。
今後のために引数%0ではなく変数でやりたかったが、情報が見つからなかった。
FOR文で逐次処理するのはやぼったいが、一発でやる方法は見つからなかった。
参考:というかそのまま。
参考:パターン
1-2.ファイルの存在をチェック
IF EXISTを使う
IF NOT EXIST !FILE_PATH! (call :SUB %FILE_PATH% %FILE_PREFIX%)
ファイルパスが存在しないときにサブルーチン":SUB"を呼んでいる。
後ろの変数は引数として渡している
1-3.サブルーチンの基礎
サブルーチンのやり方としては下記の方法が一般的。
call :ラベル
:ラベル
~処理
exit /b 0
要するにcallで呼んでexit /b 0で戻る。(/b 0は返り値)
callは他のバッチファイルやアプリも呼べる
なお、似たものにstartがあるが、こちらは終了を待たない。アプリの複数同時起動などに便利。
1-4.遅延環境変数
サブルーチンは便利だが問題も起こりやすく、特に変数が変わらないことがある。
これはちゃんと対策がある。
下記は一部抜粋なのでなんか妙だが、要するにカウンタをファイルの数だけ増やしている。
setlocal enabledelayedexpansion
SET COUNTER=0
for /F %%A IN (*.png) DO call :MAKELINE %%A
rem %COUNTER%に数値が入る
exit /b 0
:MAKELINE
SET /a COUNTER=!COUNTER! + 1
rem ~なんか処理
exit /b 0
COUNTERの値をサブルーチンの中で増やしているが、ルーチンの中で"!!"ではなく"%%"にすると、変数の更新が追いつかず、COUNTERの中身はずっと0になる。
そこで1行目の設定を行い、影響の有る変数を"!!"で囲むときちんと数が増える。
このやり方は独特で、逆に不要な変数で"!!"を使ってしまうと変数名がそのまま出て来たりするので厄介。
参考:どんなときに%なのか!なのかは使い方にもよる。
1-5.空白を含む行の出力
テキスト出力はechoを">"や">>"(追記)でやるが、スペースの有無などで上手く動かない場合がある。
そういうときはこうやる
>> %IMAGE_SET_PATH% echo # %NAME%
つまり、先に">> 出力先"を書いて、その後に"echo 内容"と続ける。
1-6.カウンタと、定期処理
カウンタを増やして、5行毎に"# ???"という数値(例:005)を入れたいものとする
setlocal enabledelayedexpansion
rem 間隔
SET INTERVAL=5
rem 行カウント
SET COUNTER=0
rem 今何回目の定期処理か
SET INTERVAL_COUNTER=0
> %IMAGE_SET_PATH% echo # 000
for %%a in (*.png) do call :MAKELINE %%a
exit /b 0
:MAKELINE
SET /a COUNTER=!COUNTER! + 1
IF !COUNTER! GEQ !INTERVAL! GOTO :NEXT
exit /b 0
:NEXT
SET /a INTERVAL_COUNTER=!INTERVAL_COUNTER! + 1
SET VAL=0
SET /a VAL=!INTERVAL_COUNTER! * !INTERVAL!
SET NAME_VAL=000%VAL%
SET NAME=%NAME_VAL:~-3%
>> %IMAGE_SET_PATH% echo # %NAME%
SET COUNTER=0
exit /b 0
まず"setlocal enabledelayedexpansion"で遅延関数有効化。
IMAGE_SET_PATHは出力先。まず">"で新規ファイル作成(更新したいので)
":MAKELINE"ルーチンでカウンタを増やす。COUNTERの数値は外部と共通なので"!"を使う。
SET /A 式 計算結果を入れる
カウンタが間隔以上になったら("GEQ")、":NEXT"ルーチンへ。
":NEXT"では、まず間隔の更新回数を増やす。
表示したいのは005,010,015,...なので、回数×INTERVALを「0付き3桁」にして取得する。
rem 文字列をくっつける
SET NAME_VAL=000%VAL%
rem 後ろ3文字のみ取得
SET NAME=%NAME_VAL:~-3%
COUNTERに「間隔をカウントする」以外の意味は今回無いので、リセットする。
SET COUNTER=0
もちろん他に幾らでも書き方はあるが、どれも正解である。
参考:0付き文字、サブルーチン、行数カウントなど
おまけ
全コードを掲載する。
要件定義が自PJ固有すぎるので、汎用性は無い。参考程度に。
setlocal enabledelayedexpansion
rem ファイル一覧を作成し、ImageSetFileとする
rem 最初に1回だけおこなうもの
rem あとから追加する場合は後ろに追加すること
rem N行ごとに# 000を記入
SET INTERVAL=5
SET IMAGE_SET_PATH=ImageSetFileList.dat
rem カウンタ
SET COUNTER=0
SET INTERVAL_COUNTER=0
SET FOLDER_NAME=
SET FilePath=%~p0
SET FilePath=%FilePath:~0,-1%
FOR /F "DELIMS=" %%A IN ("%FilePath%") DO SET FOLDER_NAME=%%~nxA
> %IMAGE_SET_PATH% echo # 000
for %%a in (*.png) do call :MAKELINE %%a
exit /b 0
:MAKELINE
SET TARGET=%1
SET FILE_PREFIX=!TARGET:~0,-5!
SET FILE_PATH=!FILE_PREFIX!.dat
>> %IMAGE_SET_PATH% echo data\image\Stand\%FOLDER_NAME%\!FILE_PATH!
rem
SET /a COUNTER=!COUNTER! + 1
IF !COUNTER! GEQ !INTERVAL! GOTO :NEXT
exit /b 0
:NEXT
SET /a INTERVAL_COUNTER=!INTERVAL_COUNTER! + 1
SET VAL=0
SET /a VAL=!INTERVAL_COUNTER! * !INTERVAL!
SET NAME_VAL=000%VAL%
SET NAME=%NAME_VAL:~-3%
>> %IMAGE_SET_PATH% echo # %NAME%
SET COUNTER=0
exit /b 0
出力例:
# 000
data\image\Stand\KesaMae\Aozame.dat
data\image\Stand\KesaMae\Ase.dat
data\image\Stand\KesaMae\BH.dat
data\image\Stand\KesaMae\F1nirami.dat
data\image\Stand\KesaMae\F2odoroki.dat
# 005
data\image\Stand\KesaMae\F3attack.dat
...
この記事が気に入ったらサポートをしてみませんか?