バッチの小ネタ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

...

この記事が気に入ったらサポートをしてみませんか?