#はじめに
この投稿は、2作目です。より基本的なことが1作目:.bat初心者・未経験者に贈るコマンド集に書いてあります(一部重複あり)。
また、いつも通り冗長な上、今回は本当に自分用の走り書きレベルで、内容に関しても普通は使わないようなこと(ゲーム向け?)がそこそこ書いてあります(意味が無いとも言います)。
そのためかなり偏っており、多分ですが本当の未経験者には辛いと思われます。【変数】【分岐】とは何か、が分かればある程度は大丈夫だと思います。たぶん。
#概略(★は難易度と需要のなさ)
- 1.@echo offとは★
- 2.遅延環境変数★★★
- 3.call call call★★(需要はなさそう)(でも重要?)
- 4.カレントディレクトリの移動★
- 5.for文①:回数ループ★★
- 6.for文②:検索・抽出★★★
- 7.set /aの便利機能★
- 8.forループとgotoループの違い★
- 9.テキストファイルを通したデータの移動★★★(需要はry)
- 10.変数を保存する方法いろいろ(需ry)
- まとめ
#1.@echo offとは
@echo off
@……これが書かれた行のコマンドを表示しない。
実行結果はその限りではないため、実行結果を表示しない場合はNULLに捨てる(>nul)。
echo……後に書かれた文字列を表示する。
off……echoコマンドのオプション。読み込まれたコマンドを表示しない。すべての行に@が付いているのと同じ挙動になる。
#2.遅延環境変数
@echo off
set a=1
set /a a+=1& echo %a%
pause>nul
【実行結果:1】
変数は、その行に差し掛かった時に行内が全部読み込まれる。
そのため、この例では3行目に入った瞬間(a=1のとき)にecho 1と読み込まれてしまう。
それを防ぐのが、遅延環境変数である。文字通り、環境変数の読み取るタイミングを遅延させることが出来る。
遅延環境変数は、通常の%a%といった囲み方ではなく、!a!とエクスクラメーションマーク(びっくりマーク)で囲まれる。これを使うと、その変数は行に差し掛かった時ではなくその変数に差し掛かった時に行われる。
また、バッチファイル内で一回でも遅延環境変数を使う場合は、それを明記する必要がある。そのためには、
setlocal enabledelayedexpansion
と入力しなくてはならない。setコマンドではないため、setとlocalの間にスペースを入れないようにすること。
@echo off
setlocal enabledelayedexpansion
set a=1
set /a a+=1& echo !a!
pause>nul
【実行結果:2】
このコマンドの真価は、後述のfor文の中で滅茶苦茶発揮される。絶対に理解が必要。
#3.call call call
xという数字の変数を1,2,3…と増やしていったとき、%number1%,%number2%,%number3%…を表示したい。
この時、素直に%number%x%%とすると、先に%number%が読み込まれてしまい、x%%が残りコマンドが機能しない。
さてさて困った…。
これの解決方法はふたつ。
一つ目は、先述の遅延環境変数を使い、!number%x%!とする。さながら数学のカッコと中カッコのように働き、正常に機能する。
が、例えばさらにその数字を変数の中に入れたいときは?数学の大カッコに当たるようなものは存在しない。
ならどうするか。こうすればいい。
@echo off
set x=1
set number1=100
set function100=目標
rem とする。
rem この"目標"という文字をxを使って表示するには、
call call echo %%%%function%%number%x%%%%%%%
rem とすればよい。何を言っているのか分からない?そうだな…
pause>nul
まずは、:.bat初心者・未経験者に贈るコマンド集に載っている「%2つで表わす理由(%%は%ひとつと認識される)」を理解すること。
その前提だが、callコマンドにはその後に書かれたコマンドを読み込んで実行する役割がある。(ほかにも役割はあるが、割愛する。)
つまり、あの%だらけのコマンドは、
call call echo %%%%function%%number%x%%%%%%%
↓
call echo %%function%number1%%%
↓
echo %function100%
と認識されることになる。入れ子構造…とは違う気がするが、そんな感じでいい。
#4.カレントディレクトリの移動
cd %~dp0
と入力すると、%cd%という変数に「そのバッチファイルが入っているフォルダ」のパスが入る(.batの1段階上まで)。
dpの他にもいろいろ種類はあるのだが、筆者はほとんどこれしか使わないんで他は覚えてないです。【バッチファイル %~dp0】とかでググればいろいろ出てくると思われる
#5.for文①:回数ループ
for /l %%i in (初項,公差,末項) do (処理)
%%iについては、iでもpでも何でもいいアルファベット1文字。大文字小文字は区別される!!!
初項…はその通り。0,1,10なら%iに0から1刻みで10まで数を入れて、そのあとに書いてある処理を実行する。
%iでなく%%iと記述する理由はお察しの通り。というか先述
for /l %%i in (1,1,13) do (
set aih[%%i]=!aitp%%i:~0,1!
set ail[%%i]=!aitp%%i:~1,1!
)
こんな感じで、処理は複数行に跨って書ける。が!!!(重要)
先ほど説明した通り、普通の変数は行に差し掛かった途端すべて読み込まれる。この例のように複数行に分けても、カッコの中なので一文と認識される。
また、%%iなどのfor文中限定の変数は【計算式に入れられない!】入れる場合はset num=%%iなどとする必要がある。
難易度は高いが、大丈夫。次はもっと高い。
#6.for文②:検索・抽出
cd %~dp0
set num=0
for /f "delims=" %%i in ('findstr /b あ %cd%\database.txt') do (
set num+=1
set result!num!=%%i
)
このコマンドでは、【このバッチファイルと同じフォルダにあるdatabase.txtの各行から】、【「あ」という文字を含む行を探し】、【該当した行を丸ごとresult1,2,3…に突っ込んでいく】という処理をしている。
詳しく解説しよう。
for /fは定型文だ。"delims="は、「丸ごと」の部分である。これが無いと、取得した行にスペースがあった場合そこで変数が分割されてしまう。ここの部分にはほかにも、usebackqやtokensなど様々あるのだが、それはまたの機会に(機会があるとは言ってない)。
%%i in はすでに5章で述べたとおり。
カッコの中は、自分が行いたいコマンドを入れる。別にfindstrでなくともよい。
「あ」の部分に変数を入れようとしたら正常に動かなかった記憶があるので、筆者は
('call findstr /b %n% %cd%\database.txt')
としている。正直あまり記憶にないうえ、callは無駄についていても特に影響がないので、検証はしていない。
do ( 以降は解説しない。5章と同じ。
これを一体どう使うのか?については、後述する。
#7.set /aの便利機能
set /a a=a+2
は、
set /a a+=2
と書ける。
set /a a+=1
set /a b-=3
set /a c*=100
といった、複数の計算は、
set /a a+=1,b-=3,c*=100
とまとめられる。
#8.forループとgotoループの違い
forループとは、5章で述べた回数ループの事。
それと同じことを、gotoでも行える。
5章にあったコマンド
for /l %%i in (1,1,13) do (
set aih[%%i]=!aitp%%i:~0,1!
set ail[%%i]=!aitp%%i:~1,1!
)
は、gotoで表わすと
set loop=0
:label
set /a loop+=1
set aih[%loop%]=!aitp%loop%:~0,1!
set ail[%loop%]=!aitp%loop%:~1,1!
if %loop% neq 13 goto label
となる。
どう見ても長くなってしかいないが、こちらにもメリットがある。
メリット① for文と違い、loopという変数に回数が残る。
(loop neq 13 の13の部分の値が定数で無い場合などに、どこまでループ処理したかを記録しておける。)
メリット②for文では遅延環境変数が多くなる(2章参照)が、gotoループでは1文扱いにならないので、管理が楽
当然デメリットもある…というか、長いのがデメリットである。
…これを見てほしい。(読まなくていい。)
:doraset
set /a dora%usedloop%=(%random%*136/32768)+1
call call set usedthis=%%%%used%%dora%usedloop%%%%%%%
if %usedloop% == 1 if %usedthis% == 1 goto doraset
set used!%dora%usedloop%!=1
if %usedloop% == 9 set usedloop=1& goto rinsyanset
set /a usedloop+=1
goto doraset
:rinsyanset
set /a rinsyan%usedloop%=%random%*136/32768+1
call call set usedthis=%%%%used%%rinsyan%usedloop%%%%%%%
if %usedthis% == 1 goto rinsyanset
set used!rinsyan%usedloop%!=1
if %usedloop% == 4 set usedloop=1& goto haipaiset
set /a usedloop+=1
goto rinsyanset
:haipaiset
if %testmode% == 1 goto aihaipaiset
set /a tehai%usedloop%=%random%*136/32768+1
call call set usedthis=%%%%used%%tehai%usedloop%%%%%%%
if %usedthis% == 1 goto haipaiset
set used!tehai%usedloop%!=1
goto aihaipaiset
:aihaipaiset
set /a aitehai%usedloop%=%random%*136/32768+1
call call set usedthis=%%%%used%%aitehai%usedloop%%%%%%%
if %usedthis% == 1 goto aihaipaiset
set used!aitehai%usedloop%!=1
if %usedloop% == 13 set usedloop=0& goto ripai1
set /a usedloop+=1
goto haipaiset
…4つのラベルをusedloopの値を変えながら何往復かしているのだが…もうお分かりだろう。
**gotoでループさせる内容が多ければ多いほど、時間がかかる。**の一点が、最大のデメリット。(あと、ラベルを転々とするので見づらい)
forも多ければ当然時間がかかるのだが、gotoのほうが文章が長くなるというのは本章の最初に示したとおりである。
#9.テキストファイルを通したデータの移動
6章のデータ抽出と、書き込み(echo %num%>>なんとかかんとか.txt)を組み合わせれば、変数をテキストファイル経由でセーブ・ロードできる。
詳しくは、.batでタイピングゲームを見てほしい。ここまでの事を理解していれば、何をやっているかは分かる。
また、データベースのようにして使うこともできる。
これは、筆者の好きなゲームの情報なのだが(そこはどうでもいい)、
G:東方アレンジ_S:色は匂へど 散りぬるを_A:幽閉サテライト(Arranged:Iceon) feat. senya_B:138_L:3 108_M:5 204_B:7 304_N:- -
G:東方アレンジ_S:INFINITE WORLD_A:SOUND HOLIC feat. Nana Takahashi_B:167_L:3 112_M:6 235_B:8 422_N:- -
G:東方アレンジ_S:お嫁にしなさいっ!_A:ARM+夕野ヨシミ_B:180_L:2 82_M:5 193_B:7 313_N:- -
G:東方アレンジ_S:ケロ⑨destiny_A:Silver Forest feat. めらみぽっぷ_B:174_L:2 158_M:6 370_B:9 533_N:- -
G:東方アレンジ_S:しゅわスパ大作戦☆_A:SOUND HOLIC feat. Nana Takahashi_B:140_L:2 117_M:5 217_B:8 398_N:- -
G:東方アレンジ_S:チルノのパーフェクトさんすう教室_A:ARM+夕野ヨシミ feat.miko_B:175_L:2 80_M:6 270_B:8 481_N:9 584
G:東方アレンジ_S:月に叢雲華に風_A:幽閉サテライト(Arranged:Iceon) feat. senya_B:160_L:4 117_M:6 199_B:8 315_N:- -
G:東方アレンジ_S:待チ人ハ来ズ。_A:豚乙女_B:160_L:3 107_M:5 182_B:7 353_N:- -
G:東方アレンジ_S:魔理沙は大変なものを盗んでいきました_A:ARM+夕野ヨシミ feat. 藤咲かりん_B:170_L:3 137_M:6 252_B:9 543_N:10 697
とこんな感じでデータを保管して、特定のワード(この例では「G:」「B:」など)をサーチして確認!みたいなことが出来る。需要があるかどうかは神のみぞ知る。
#10.変数を保存する方法いろいろ
上で述べたように、テキストファイルを経由して変数を保存することが出来るが、ほかにも保存する方法が無いか、と筆者は考えた。
setxという残り続ける変数の設定方法もあるにはあるのだが、たくさんの種類のバッチファイルを作っているとどうしても競合することがある。
そして筆者は考えた。「そのバッチファイルに書き足せばいいじゃん!」
その結果できたのが.bat(バッチファイル)でポーカー(完成版)である(宣伝)。
あまりたくさんの変数を保存する必要があるとこれは使えないのだが、そうでなければ十分実用的。何より、ファイルが増えないという利便性は大きい。
#まとめ
かなり分かりづらい解説&所々自分に向けたコメントになっており、大変申し訳ありません。
普通に使う分には使わない知識ばかりだったかもしれませんが、前作で飛ばしたforの解説を(端折りながら)入れてみたり、バッチではなかなか厳しいと思われる変数の保存方法にも手を出してみましたので、バッチファイルでゲームを作りたい方にはそこそこ役だったのではないでしょうか。
batchはチューリング完全なので、(理論上は)「計算で出来るすべての事はバッチで出来る」のです。極論、バッチファイルでは論理演算ができますので、バッチファイルでOSが行う処理全てを再現することはできる(はず)です。
それと比べたら、たかだかゲームひとつくらい、とても簡単なことです。
皆さんも、バッチファイルでゲームを作ってみてはいかがでしょうか。まずはじゃんけんなんかお勧めです。