バッチファイル(英: batch file)とは、MS-DOS、OS/2、Windowsでのコマンドラインインタプリタ(シェル)に実行させたいコマンド(指令または命令)列をテキストファイルに記述したもの。バッチファイルを実行すると、シェルプログラム(一般に`COMMAND.COM`や`cmd.exe`)がそのファイルを読み、その中のコマンドを(通常)一行ずつ実行する。バッチファイルはUNIXおよびUnix系オペレーティングシステムのシェルスクリプトに相当する。主に複数の処理をまとめて記述しておき、繰り返し実行するバッチ処理のために用いられる。

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

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

## 歴史

マイクロソフトのDOSとWindowsのバッチプログラミングはこれらのオペレーティングシステム (OS) 製品のリリースとともに発展してきた。これらのOSに付属するコマンドインタプリタは2つの動作モードを持つ。1つは対話モード(コマンドプロンプトに従ってユーザーがコマンドを入力すると即座に実行される)、もう1つはバッチモード(あらかじめ設定されたコマンド列を実行する)である。どちらのモードも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`も未だに搭載されている。なお、cmd.exeに対しては「コマンド プロンプト」という名前のショートカットが既定で作成されており、便宜上GUIに表示される名前としても各所で使用されているが、一般的な技術用語のコマンドプロンプトとは別物である。cmd.exeで利用可能なコマンドは「Windowsコマンド」とも呼ばれる。

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

## 代表的なコマンド

以下ではWindows NT系のcmd.exeで利用できるWindowsコマンドの仕様に従って解説する。構文規則において、`[`と`]`で囲まれたものはオプション(省略可能)であることを意味する。詳しくは公式リファレンスを参照のこと。`/?`オプションを付けてコマンドを実行することで、そのコマンドのヘルプを表示することもできる。

BASICやPascalに代表される古いプログラミング言語や、MS-DOSおよびWindowsなどのファイルシステムではアルファベットの大文字・小文字を区別しない仕様となっている影響から、バッチファイルもほとんどの場面で大文字・小文字を区別しない。歴史的な経緯から、ヘルプのメッセージ内ではコマンド名やオプション名が大文字アルファベットで表記されているが、本記事では引用を除いて小文字アルファベットで記載するものとする。

### echo

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

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

### rem

コメント行は`rem`で始める。`rem`もコマンドの一種である。コメントや注釈を意味するremarkの略で、BASIC系言語の`rem`ステートメントと類似のものである。

### cls

テキスト画面をクリア(消去)し、ウィンドウを既定の状態にする。

### color

テキスト画面の背景色と前景色を変更する。16進数の`0`から`f`まで全16色のカラーコードが割り当てられており、引数として背景色と前景色を2桁の16進数で指定する。1桁の16進数を指定した場合、前景色として使われ、背景色は既定値となる。背景色と前景色に同じ値を指定した場合は失敗する。引数を指定しなかった場合、背景色と前景色が既定値にリセットされる。

### call

引数で指定した別のバッチファイルや、引数で指定したラベルを持つプログラムを呼び出し、制御を移す。

### if

多くの汎用プログラミング言語における条件分岐構文の1つとしてif文があり、バッチファイルでも`if`コマンドとしてサポートされている。

基本構文:

拡張構文:

既定では条件が真の場合にサブコマンドを実行するが、`not`を指定すると条件が偽の場合にサブコマンドを実行する。

`ERRORLEVEL`は直前のコマンドの実行結果(終了ステータス)を格納しているシステム環境変数の1つであり、通例`0`が正常終了を、それ以外が異常終了(エラーコード)を意味する。`if`コマンドの基本構文では後続指定する`<number>`の値以上である場合に真となる。

`exist`は後続指定するファイルが存在するかどうかをテストし、存在する場合は真となる。

#### 例

カレントディレクトリに test.txt というファイルが存在するかどうかに応じて処理を分岐する。存在する場合は拡張子`.txt`が関連付けられているアプリケーションソフトウェアで開く。

### for

C言語を代表とする多くの汎用プログラミング言語はループ構文の1つとしてfor文をサポートするが、バッチファイルの`for`コマンドはforeach文に相当する。もともとファイルやディレクトリ(フォルダー)やテキスト文字列の集合(set)の中から各要素に対して指定コマンド(サブコマンド)を実行するものであるが、数値の範囲を指定することもできる。

基本構文:

ここで、`<variable>`は`for`コマンド専用の変数であり、アルファベット1文字のみが利用可能である。大文字と小文字は区別される。正規表現で書くならば、許可される文字は`[A-Za-z]`となる。`for`コマンドをコマンドラインシェル上で直接実行する場合は`%i`のようにパーセント記号を1つだけ使う。バッチファイル内に記述する場合は`%%i`のようにパーセント記号を2つ使う。

`<set>`にはファイルのグループを1つ以上指定することもできる。ワイルドカード(`*`および`?`)を利用することもできる。以下は有効な集合の例である。

`<commandlineoptions>`はサブコマンド`<command>`に対するオプションである。

#### コマンド拡張

`for`の直後にスペースを空けて、`for`コマンド自体に対するいくつかの拡張オプションを指定することも可能である。

##### ディレクトリのみ

ファイルではなくディレクトリのみを対象とする。

##### 再帰

サブディレクトリも対象にする。

##### 値の範囲で反復

変数の値を開始値`<start#>`と終了値`<end#>`の間でステップ量`<step#>`だけ変化させながら、指定コマンドを反復実行する。

まず変数に開始値が代入され、指定コマンドが実行される。次に変数の値をステップ量だけ変化させ、再び指定コマンドを実行する。ステップは正の数だけでなく負の数も指定可能である。ステップが正のとき、変数の値が終了値より大きくなった場合は指定コマンドを実行せず終了する。ステップが負のとき、変数の値が終了値より小さくなった場合は指定コマンドを実行せず終了する。

### cd

指定したディレクトリを「カレントディレクトリ」として設定する。便宜上の概念から、指定ディレクトリに「移動する」とも言われる。相対パスは、`cd`で設定したカレントディレクトリを基準に扱われるようになる。引数を指定しなかった場合、カレントディレクトリのフルパスを出力する。

### dir

指定したディレクトリの中のファイルおよびサブディレクトリのリストを表示する。引数を指定しなかった場合はカレントディレクトリが対象となる。オプションを設定することで、条件に合致する特定のファイルのみ表示することもできる。

このコマンドとリダイレクトを使ってテキストファイル形式のファイルリストを作ることなどもできる。

### shift

バッチファイルにおいて、バッチ引数の位置を変更する。

バッチファイルをコマンドラインシェルから実行する際は10個以上の引数を指定することもできるものの、バッチファイルからは`%0` - `%9`の範囲の引数しか扱えない仕様となっている(`%0`はバッチファイルの名前を表すため、実質的には9個の引数が使用可能)。

`shift`コマンドによって、引数の値が1つ前の引数にコピーされる。つまり`%1`の値は`%0`にコピーされ、`%2`の値は`%1`にコピーされる。これにより、バッチファイルで疑似的に10個以上の引数を扱えるようになる。

オプションとして`/n`があり、シフトを開始する引数の番号を指定できる。`n`には`0`から`8`までの番号を指定できる。例えば`shift /2`は`%3`を`%2`に、`%4`を`%3`にシフトするが、`%0`と`%1`は変更されない。

#### 例

起動コマンド行:

バッチファイル test.bat の内容:

出力:

### set

「cmd.exe環境変数」を表示・設定・削除する。引数なしで`set`コマンドを実行した場合、現在設定されている環境変数の一覧を表示する。

基本構文:

cmd.exe環境変数は、システム環境変数やユーザー環境変数とは異なり、起動中のcmd.exeのインスタンスおよびそこから起動した子プロセスにのみ影響する一時的な環境変数である。

#### 動的な環境変数

`set /?`で表示されるヘルプには、動的な環境変数に関する注意事項が記載されている。

コマンド拡張機能が有効な場合、SET によって表示される変数の一覧には現れないいくつかの動的な環境変数があります。
これらの変数の値は、変数の値が展開されるときに動的に計算されます。
ユーザーがこれらの名前の変数を明示的に定義する場合、その定義は下記の動的な定義を無効にします。

続いて列挙される動的な環境変数とその説明文(日本語版)の引用を以下に記載する。

| 環境変数 | 説明文 | 備考 |
| --- | --- | --- |
| `%CD%` | 現在のディレクトリ文字列に展開します。 | カレントディレクトリを表す。`cd`コマンドなどで変更可能。 |
| `%DATE%` | DATE コマンドと同じフォーマットで現在の日付に展開します。 | システム時刻に依存する。`date`コマンドでも変更可能。既定の表示形式はシステム設定に依存する。 |
| `%TIME%` | TIME コマンドと同じフォーマットで現在の時刻に展開します。 | システム時刻に依存する。`time`コマンドでも変更可能。既定の表示形式は`hh:mm:ss.ms`であるが、時間 (hour) 部分が1桁台の間は先頭がゼロではなく空白となる。 |
| `%RANDOM%` | 0 から 32767 の間の任意の 10 進数に展開します。 | 疑似乱数を生成する。 |
| `%ERRORLEVEL%` | 現在の ERRORLEVEL の値に展開します。 | 直前のコマンドが正常終了したか、または異常終了したかを整数値で表したもの。`0`が正常終了で、それ以外が異常終了である。通例`if`コマンドと組み合わせて使う。 |
| `%CMDEXTVERSION%` | 現在のコマンド プロセッサ拡張機能のバージョン番号に展開します。 | 通例`if`コマンドと組み合わせて使う。 |
| `%CMDCMDLINE%` | コマンド プロセッサを起動したオリジナル コマンド ラインに展開します。 | - |
| `%HIGHESTNUMANODENUMBER%` | このコンピューター上の最大の NUMA ノード番号に展開します。 | 詳細はNUMAアーキテクチャのシステムサポートに関する情報を参照のこと。 |

これらの環境変数の値を`set`コマンドで変更することはできない。新たに同名のcmd.exe環境変数が生成され、動作がオーバーライド(上書き)されてしまうだけである。

### setlocal/endlocal

`set`コマンドで作成する変数はcmd.exe環境変数であり、既定でグローバル変数のような性質を持つ。つまり、バッチファイル内のどこからでもその変数にアクセスすることができてしまい、またcmd.exeのインスタンスが生き残っている限り、バッチファイルの終了後もその変数が維持されてしまう。特定のバッチファイル内限定、あるいはサブルーチンのような一部の領域でのみ使用することが想定されている変数は、事前に`setlocal`コマンドを実行しておくことでローカル変数とすることができる。

また、`endlocal`コマンドを使用することで環境変更のローカル化を終了し、対となる`setlocal`コマンドが実行される前の環境変数の状態を復元することができる。

#### 環境変数の遅延展開

以下のように環境変数を`if`コマンドの中で書き換えるケースを考える。

実行結果:

`my_variable`の値は`if`コマンドの実行後には確かに書き換わっていることが確認できるが、`if`コマンドの実行中に(サブコマンドグループの実行中に)参照すると、直感に反して書き換え前の値が出力されてしまう。これは、環境変数の展開が、既定では各コマンド行の解析時に一度だけ実行されるモードになっているからである。

事前に`setlocal enabledelayedexpansion`コマンドを実行し、かつ`%`の代わりに`!`を使って環境変数を囲むことで、環境変数を実行時に(サブコマンドによって実際に参照されるタイミングで)遅延展開することが可能となる。

実行結果:

## 拡張子による動作の違い

Windows NT系では`.cmd`だけでなく従来の`.bat`もバッチファイルの拡張子として使用可能だが、動作に微妙な差がある。

以下のコマンドを記述したバッチファイルがあるとする。実行すると、`setlocal`は成功して環境変数`ERRORLEVEL`が`0`に設定され、`color 00`は失敗して環境変数`ERRORLEVEL`が`1`に設定され、`set my_variable=100`は成功する。

拡張子を`.cmd`とした場合の実行結果:

拡張子を`.bat`とした場合の実行結果:

最後の出力結果に違いが生じる原因は、`.cmd`では`set`コマンドは成否にかかわらず常に`ERRORLEVEL`を変更し、成功した場合は`ERRORLEVEL`が`0`にリセットされるのに対し、`.bat`では`set`コマンドは失敗した場合にのみ`ERRORLEVEL`を変更する動作となるからである。つまり、`.cmd`のほうがいくらか安全な動作をする。`.bat`の動作は直感的ではなく、驚き最小の原則に反しているといえる。ただし、このルールに従わないコマンドもいくつかあり、例えば`echo`や`rem`は、成否およびバッチファイルの拡張子によらず常に`ERRORLEVEL`を変更しない。

## 例

- 単純なバッチファイルの例:

画面出力:

- Hello world

画面出力:

- Fizz Buzz

画面出力:なし

- FFmpegでエンコード バッチファイルの置かれたディレクトリを終了するまで10秒おきに監視して、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ファイルを発見すると順次エンコードする。

## 互換コマンドインタプリタ

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

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

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