バッチファイル

バッチファイル（）とは、MS-DOS、OS/2、Windowsでのコマンドプロンプト（シェル）に実行させたい命令列をテキストファイルに記述したもの。バッチファイルを実行すると、シェルプログラム（一般にCOMMAND.COMやcmd.exe）がそのファイルを読み、その中のコマンドを（通常）一行ずつ実行する。バッチファイルはUNIX系オペレーティングシステムのシェルスクリプトに相当する。

DOSのバッチファイルの拡張子は.BATである。他の環境のバッチファイルの拡張子は様々である。例えば、Windows NTやOS/2では.CMD が使われており、 というフリーウェアでは .BTM が使われている。

AUTOEXEC.BATはブート処理の中で実行される特別なバッチファイル（自動実行バッチファイル）である。

歴史 
マイクロソフトのDOSとWindowsのバッチプログラミングはこれらのオペレーティングシステム (OS) 製品のリリースとともに発展してきた。これらOSに付属するコマンドインタプリタは2つの動作モードを持つ。一つは対話モード（コマンドプロンプトに従ってユーザーがコマンドを入力すると即座に実行される）とバッチモード（予め設定されたコマンド列を実行する）である。どちらのモードもUNIXのシェルや1980年代初期のCP/Mなどのコマンドインターフェイスがその考え方のベースとなっている。

MS-DOSオペレーティングシステムのバッチプログラム用インタプリタはCOMMAND.COMである。MS-DOS用バッチプログラムのうち比較的単純なコマンドはCOMMAND.COM自身が処理し（内部コマンド）、複雑なものは別の実行ファイルを呼び出して処理する（外部コマンド）。この系統のバッチプログラミングはMS-DOSからWindows 95、Windows 98、Windows Me（Windows 9x系）まで発展していった。

Windows 2000およびWindows XP以降はMS-DOSではなくWindows NTに基づいている。この系統（Windows NT系）ではcmd.exeというコマンド行インタプリタが使われ、COMMAND.COMとはある程度の互換性がある。MS-DOSのいくつかの機能が削除されているが、MS-DOSやMS-DOSベースのWindowsにはない新たな機能も多く追加されている。互換性維持のためCOMMAND.COMも未だに搭載されている。

2006年には.NET Frameworkを基盤に動作する、モダンなオブジェクト指向のシェル環境としてWindows PowerShellがリリースされた。Windows PowerShellではdirなどの従来のWindowsコマンドに対するエイリアスが用意されており、完全ではないがある程度の互換性がある。PowerShellはWindows以外の環境にも.NET Coreベースで移植されている。

代表的なコマンド

echo 
echoコマンドは標準出力にメッセージを表示する。メッセージ文字列をダブルクォーテーションやシングルクォーテーションなどで囲む必要はない。

また、echo onおよびecho offでコマンドエコーのON/OFFを切り替えることができる。コマンドエコーは既定でONになっており、各コマンド行を実行する前に標準出力にその内容を表示する。この動作は通常必要とされないので、echo off コマンドをバッチファイルの最初に記述してそれを防ぐ。しかし、そのままでは echo off コマンド自体は表示されてしまう。単価記号 @ をコマンド行の先頭に置くと、その行は表示されないようになっているので、多くのバッチファイルには @echo off という行が先頭にある。

rem 
コメント行はremで始める。remもコマンドの一種である。

cls 
テキスト画面を削除する。

call 
別のバッチファイルやラベルで指定したプログラムに処理を移す。バッチファイルにはローカル変数とグローバル変数の概念があり、サブルーチンの中でメインルーチンにある変数と同じ名前の変数を使っても区別される。

for 
他の多くのプログラミング言語と同じように指定した回数ループすることができるコマンドであるが、それのみならずフォルダ内のすべてのファイルを確認しそれらのファイルに対して処理を行うなどと行ったこともできる。基本的には、for (オプション) %%変数名 in (ループの対象) do(コマンド)という書式になる。オプションとして何も指定しない場合はinで指定したディレクトリの中のファイル名１つを%%のあとに指定したアルファベット一文字の変数に代入してからdoの中の処理を行う。ファイルが無くなったら中断する。つまりファイルがなくならないようなプログラムを作ってしまうと無限ループになる。/rをオプションに指定すると、サブディレクトリまでも対象にする。

オプションとして/dを指定すると、inで指定したディレクトリの中のディレクトリ名が１つ変数に代入されてから、doの中の処理を行う。

/lは一般的なプログラミング言語における指定した回数のループを行う。その場合の書式は次のようになる。for /l %%変数 in (開始値、増分、終了値) do コマンドまず開始値で指定した数値が変数に代入され、doの中の処理が行われる。doの中の処理が終わると、変数の値が増分値で指定した分だけ増加し、またdo内の処理が行われる。変数の値が終了値に達すると処理が終了する。

cd 
指定したディレクトリに移動することができる。cdで移動したディレクトリより階層が深いところにあるファイル、フォルダは、相対パスで参照可能になる。

dir 
指定したディレクトリの中のファイルのリストを表示する。これを使ってテキストファイル形式のファイルリストを作ることができる。オプションを設定することで特定のファイルのみ表示することもできる。

shift 
これを実行すると呼び出し時に渡された引数を一つずらすことができる。オプションはない。

使用例:バッチファイルの引数は、仕様によって10個未満(9個以下)までしか引数を指定できない。なので、10つ以上指定する場合は、shiftコマンドを利用する。

起動引数:test.bat ar1 ar2 ar3 ar4 ar5 ar6 ar7 ar8 ar9 ar10コード:@echo off
shift
echo 第9引数は%9です。出力:第9引数はar10です。

特殊な変数<ref>{{Cite web |title=バッチファイルで変数を使う |url=https://jj-blues.com/cms/wantto-variableinbatfile/ |website=知識ゼロからのwindowsバッチファイル超入門 |access-date=2022-08-08 |language=ja |first= 
バッチファイル(コマンドプロンプト)には、コマンドの後の返り値、呼び出し時の引数、システムの設定などで値が変わる特殊な変数がある。

%1,%2,%3...%9 
これは変数というより引数に近く、バッチファイルが呼び出された時に指定された引数を前から順番に1,2,3,4...の順で参照できる。注意点として、引数は10個までしか指定できないということ。10個以上指定する場合は、shiftコマンドを利用する。

%CD% 
cdコマンドなどで指定したディレクトリのパス。この値はcdコマンドなどで変えられる。

%DATE% 
現在の日付。これはシステムに依存する。システムの設定や、dateコマンドで変更できる。

%TIME% 
現在の時刻。これもシステムに依存する。形式はhh:mm:ss.msである。

%RANDOM% 
0から32767までのランダムな整数。for文の中で複数回呼び出しても値は変わらないが、for文の外ならば呼び出されるごとに値が変わる。ちなみに、32767は符号なし15bit整数の最大値である。

%ERRORLEVEL% 
直前のコマンドが正常終了したか、または異常終了したかを数値で表したもの。一般的に、0が正常終了で、-1が異常終了である。これはif文と組み合わせて使う。

%CMDEXTVERSION% 
現在の拡張機能のバージョン番号。cmdコマンドで拡張機能を指定してコマンドプロンプトを起動できる。

%HIGHESTNUMANODENUMBER% 
コンピューター上の最大NUMAノード番号。使うことは滅多にない。

変数の読み込みタイミング 
set num=1 
if %num% == 1 (
    set /a num+=1 
    echo %num%
)
pause このプログラムは、変数numを表示するように書いているので、変数numに加算されて「2」と表示されるはずが、このコードでは「2」ではなく「1」と表示される。この原因は、if文に入った時点で変数numが固定(厳密には展開)されるので、変数に加算はされるが表示するものは「1」で固定されているので、「1」と表示される。

これを回避するには、2つの方法がある。

「!」で囲って参照する方法 
この変数が展開されるのを防ぐには、「!」で囲うという方法がある。

「!」で参照すると、その変数を読み込むタイミングが、『行に入った瞬間』から『その変数を使うコマンドにたどり着いた瞬間』になる。

そのため、上記のコードを「!」で囲うと、通常通り加算されて「2」と表示される。

setlocalコマンドを使う方法 
もう一つの方法は、setlocal enabledelayedexpansionを先頭に記述する方法だ。

これを使うことにより、「!」で囲った時と同じ効果が得られる。

ちなみに、setlocal enabledelayedexpansionを解除する方法は、解除したい行でendlocalを入力するだけだ。

例 
 単純なバッチファイルの例：
@echo off
cls
echo.
echo Hello World, press any key to start AProgram.exe!
pause > nul
AProgram.exe
echo.
echo AProgram has finished whatever it was doing. Have fun today!画面出力:Hello World, press any key to start AProgram.exe!

AProgram has finished whatever it was doing. Have fun today!
 Hello world
@echo off
echo Hello world!!
pause > nul画面出力:Hello world!!
 Fizz Buzz
 3の倍数ならFizz、5の倍数ならBuzz、15の倍数ならFizz Buzzと表示し、FizzBuzz.txt に結果を出力
@echo off
setlocal enabledelayedexpansion
cd /d %~dp0
if exist %cd%\FizzBuzz.txt del %cd%\FizzBuzz.txt
for /l %%i in (1,1,100) do (
set echo=
set /a f=%%i%%3,b=%%i%%5
if !f!==0 set echo=!echo!Fizz
if !b!==0 set echo=!echo!Buzz
if "!echo!"=="" set echo=%%i
echo !echo!>>%cd%\FizzBuzz.txt
)画面出力:なし
 FFmpegでエンコード  バッチファイルの置かれたディレクトリを終了するまで１０秒おきに監視して、tsファイルを発見次第バッチファイルと同じフォルダに置かれたffmpeg.exeでmp4にエンコードしたあと、元のファイルを削除する。  エンコードされたファイルが既に存在する場合は上書きする。echo off
cd %~dp
:loop
for %%i in (*.ts) do (
 call :encode %%i%
)
timeout 10
goto :loop

:encode
ffmpeg.exe -i "%1" -vf bwdif=1 -c:v libx264 -c:a copy -bsf:a aac_adtstoasc ^
-preset fast -aspect 16:9 -b:v 5500k -y "%~n1.mp4"
del %1
exit /bまず、forループでファイルが有るかどうかチェックする。見つかったファイルは:encodeというサブルーチンに渡される。これはエンコード後のファイル名をつける際の%~n1で元のファイルのファイル名だけを抽出する必要があるからだ。  encodeの中でファイルをffmpegに渡してエンコードし、その後delコマンドでファイルを削除したら、サブルーチンが終了し、メインルーチンに戻る。tsファイルがまだ残っていれば再びエンコードする。なければforループから抜け出し、10秒間待機する。再びtsファイルを発見すると順次エンコードする。

互換コマンドインタプリタ
マイクロソフト以外が提供するコマンドインタプリタにも様々なコマンドインタプリタがあり、強化された機能を提供している。 はその一例である。

バッチプログラムを実行ファイルに変換するコンパイラもマイクロソフト以外からいくつか登場しているが、その品質は様々である。

IBMのOS/2オペレーティングシステムもマイクロソフトのOSと似たようなテキストベースのコマンド機能を持っている。

脚注

関連項目 
 シェルスクリプト
 バッチ処理
 フィルター - フィルタ (ソフトウェア)
 パイプ
 ジョブ
 ジョブ管理システム
 Windows Script Host
 Windows PowerShell

外部リンク 
 Windows Commands | Microsoft Docs

Windowsアドミニストレーション
オペレーティングシステムの仕組み
プログラミング