バッチファイル基礎文法リファレンス

## 改版履歴

<pre>2010年 2月11日 初版
2010年 2月13日 遅延環境変数展開を追加
2010年 2月14日 糖衣構文を追加
2010年 3月 2日 特殊な変数展開を追加
2010年 3月11日 文字列の抽出を編集
2017年 8月 1日 本稿を FC2 から Qiita へ移行
</pre>

## はじめに

### バッチファイルとは

コマンドプロンプトを起動すると、コンソールにプロンプト（C:\>）が表示され、コマンドの入力を促されます。ユーザーはキーボードからコマンドを入力することで、いろいろな処理を実行することができます。これを**コマンドコンソール機能**と言います。

しかし、決められた処理を実行するために毎回同じコマンドを一つ一つ入力していくのは面倒です。

そのため、実行するコマンドをあらかじめファイルに書いておき、そのファイルをコマンドプロンプトに読み込ませて実行させることができます。これを**バッチ機能**と言い、実行させるファイルのことを**バッチファイル**と言います。

### バッチファイルの作成

メモ帳を起動して、コマンド（echo HELLO, WORLD. など）を書きます。それを「**（任意の文字列）.bat**」または「**（任意の文字列）.com**」という名前でファイルに保存します。

なお、ファイルの一行目に `@echo off` という行を追加しておくと、一行実行される度にその行の内容がコンソールに表示される煩わしさがなくなります。

### バッチファイルの実行

コマンドプロンプトからバッチファイルを実行するには以下のようにします。

```
C:\>X.bat パラメーター
```

実行する時にパラメーターを必要としなければ、アイコンをダブルクリックするだけでも構いません。

![2017-07-30.png](https://qiita-image-store.s3.amazonaws.com/0/29814/62678b40-3103-af26-e1a3-59dca828a6b2.png)

なお、拡張子を省略して実行することもできます。

```
C:\>X
```

省略した場合、環境変数 `PATHEXT` に登録されている拡張子が順番に補われて実行されます。

```
C:\>set PATHEXT
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
```

また、標準入力を利用して実行することもできます。この時、コマンドプロンプトにはバッチファイルの内容が一行ずつ渡されて実行されます。

```
C:\>cmd.exe < X.bat
```

### ヘルプ

コマンドの後に `/?` オプションをつけて実行することで、ヘルプを参照することができます。

```
C:\>cmd /?
```

## 基礎

### 文字列の出力

`echo` コマンドを利用します。文字列は引用符でくくりません。

```bat:
echo HELLO, WORLD.
```

空行を出力するには間をあけずに `.`（ドット）を指定します。

```bat:
echo.
```

特殊な文字を出力するには `^`（ハット）でエスケープします。

```bat:
echo ^|
```

なお、特殊な文字には以下のものがあります。

```
& < > [ ] { } ^ = ; ! ' + , ` ~
```

文字列を複数行にわたって分割して指定するには行末に `^` を指定します。

```bat:
echo ^
ABCDEFGHIJKLM^
NOPQRSTUVWXYZ
```

制御文字を出力することもできます。以下は BEL（ベル文字，`CTRL + G` を入力）を入力する例です。

```bat:
echo ^G
```

### コメント

`rem` コマンドを利用します。コマンド名は REMarks（備考）に由来します。

```bat:
rem コメント
```

また、以下のように書くこともできます。これはラベルを利用した書式です。

```bat:
: コメント
```

見ためをラベルと区別するため、以下のように書くこともあります。

```bat:
:: コメント
```

### 変数

変数には環境変数，バッチ変数，`for` コマンドのブロック内だけで使用される一時変数，位置パラメーターがあります。

#### 環境変数

変数のスコープ（有効範囲）はシステム全体です。どこからでも参照することができます。

パラメーターを指定せずに `set` コマンドを実行することで環境変数の一覧を参照することができます。

```
C:\>set
```

#### バッチ変数

変数のスコープはバッチファイルを実行したコマンドプロンプトの実行コンテキストに依存します。言い換えれば、バッチファイルの中であればどこからでも参照することができます。

変数を宣言するには `set` コマンドを利用します。変数に明確な型はありません。なお、`=`（代入演算子）の前後に半角空白を入れることはできません。

```bat:
set x=1
```

変数の値を参照するには変数名を `%` でくくります。

```bat:
echo %x%
```

遅延環境変数展開を利用する場合は、変数名を `!` でくくります。遅延環境変数展開については後述します。

```bat:
echo !x!
```

変数の宣言を取り消すには以下のようにします。

```bat:
set x=
```

なお、`setlocal` コマンドと `endlocal` コマンドを利用すれば、変数のスコープを設定することができます。

```bat:
setlocal
  set i=0
  setlocal
    echo %i%
    set i=1
    echo %i%
  endlocal
  echo %i%
endlocal
```

#### 一時変数

`for` コマンドで使用する特殊な変数で、変数のスコープはそのブロック内に限定されます。変数名は `%%英字一文字` で指定し、大文字と小文字で区別されます。

```bat:
for /f "tokens=1,2 delims=," %%a in ('echo A,B') do (
  echo 一つめの値は %%a です。
  echo 二つめの値は %%b です。
)
```

#### 位置パラメーター

バッチファイルや関数に渡されたパラメーターが格納されています。位置パラメーターの値は `shift` コマンドで参照することができます。

```bat:
:BOL
  echo %1
  shift
if not "%~1" == "" goto BOL
```

`%番号` で参照することもできますが、番号の部分には 1 から 9 までの値しか指定することができません。

```bat:
echo %1 %2 %3 %4 %5 %6 %7 %8 %9
```

`%*` で渡されたパラメーター全てを参照することができます。

```bat:
echo %*
```

なお、パラメーターが引用符付きで渡された場合、`%` と番号の間に `~`（チルダー）を追加することで、引用符を削除することができます。

`%0` でバッチファイル自体の名前を参照することができます。

```bat:
echo %0
```

#### 終了ステータス

バッチファイルは文法に従ってコマンドを並べることで成り立っています。そのため、コマンドの実行に成功したかどうか確める必要があります。コマンドの終了ステータスは環境変数 `ERRORLEVEL` の値を参照します。慣習的に値が 0 であれば成功、0 以外であれば失敗です。

```bat:
dir X.txt
if %ERRORLEVEL% neq 0 (
  echo ファイルが見つかりません。
) else (
  echo ファイルが見つかりました。
)
```

なお、バッチファイルで終了ステータスをセットするには `exit` コマンドを利用します。パラメーターには 32 ビット符号付き整数で表現できる値を指定することができます。

```bat:
exit /b 数値
```

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

遅延環境変数展開を利用すると、変数が使用された時点で初めて評価・展開されます。

`if` コマンドや `for` コマンドは一つのブロック（処理単位）として扱われるため、丸カッコの中の変数は最初に展開されます。

以下の例では、変数 t に変数 s の値が代入されることはありません。

```bat:
setlocal
  set s=
  
  if "%s%" == "" (
    set s=X
    set t=%s%
  )
  
  echo %t%
endlocal
```

しかし、遅延環境変数展開を有効にすると、`if` コマンドの中に記述した行が逐次解釈されて実行されます。

遅延環境変数展開は `setlocal` コマンドに `enabledelayedexpansion` キーワードを指定することで有効になります。

以下の例では、変数 t に変数 s の値が代入されるようになります。

```bat:
setlocal enabledelayedexpansion
  set s=
  
  if "%s%" == "" (
    set s=X
    set t=!s!
  )
  
  echo %t
endlocal
```

#### 特殊な変数展開

位置パラメーターや一時変数を `%~英字` という形式で指定することで、パス文字列からファイルに関連するいろいろな情報を参照することができます。

指定できる英字には以下のものがあります。

| 書式 | 説明                                                   | 値                                                    |
|:-----|:-------------------------------------------------------|:------------------------------------------------------|
| %~f0 | 変数を完全なパス文字列に展開                           | C:\Documents and Settings\xxxxxxxx\デスクトップ\X.bat |
| %~d0 | 変数をドライブレターに展開                             | C:                                                    |
| %~p0 | 変数をドライブレターとファイル名を除くパス文字列に展開 | \Documents and Settings\xxxxxxxx\デスクトップ\        |
| %~n0 | 変数をファイル名に展開                                 | X                                                     |
| %~x0 | 変数を拡張子に展開                                     | .bat                                                  |
| %~s0 | 変数を完全なパス文字列（8.3 形式）に展開               | C:\DOCUME~1\xxxxxxxx\デスク~1\X.bat                   |
| %~a0 | 変数をファイルの属性に展開                             | --a------                                             |
| %~t0 | 変数をファイルの更新日時に展開                         | 2010/03/01 12:34                                      |
| %~z0 | 変数をファイルのサイズに展開                           | 1024                                                  |

また、これらを組み合わせることもできます。例えば、半角空白を含むパス文字列を含まない形式に変えておくことで、いちいちパス文字列を引用符でくくる必要がなくなります。

```bat:
copy %~s0 %~dpsn0.txt
```

#### 例外処理

ありません。

#### 文法チェック

ありません。

#### デバッグ

デバッグ用のツールはありませんが、`echo` コマンドを利用することで、変数にセットされている値を部分的に参照することができます。

```bat:
処理
@echo on
問題のある処理
@echo off
処理
```

また、実行中の処理を一時停止するには `pause` コマンドを入れます。

```bat:
for /l %%i in (0, 1, 9) do (
  問題のある処理
  pause
  処理
)
```

## 数値

### 数値の表現

32 ビット符号付き整数で表現できる値を扱うことができます。

```bat:
set x=-2147483647
set x=2147483647
```

以下は文字列としては代入できますが、数値演算に利用することはできません。

```bat:
set x=2147483648
set x=0.1
```

また、8 進数や 16 進数で指定することもできます。

```bat:
set x=0xff
set x=0377
```

以下は値の先頭が 0 で始まっているため 8 進数と見なされますが、無効な値なので、数値演算に使用することはできません。

```bat:
set x=09
```

なお、`set` コマンドに `/a` オプションを指定して値を代入すると、有効な数値かどうか確認することができます。

```
C:\>set /a x=09
無効な数字です。数値定数は 10 進 (17 桁)、16 進 (0x11 桁)、
または 8 進 (021 桁) です。
```

### 数値演算

`set` コマンドに `/a` オプションを指定すると、パラメーターを式として評価させることができます。

```bat:
set /a x=1+1
set /a x=1-1
set /a x=1*1
set /a x=1/1
```

剰余（余り）を求める場合は `%` ではなく `%%` と書きます。

```bat:
set /a x=3%%2
```

丸カッコでくくることで演算の優先順位を変えることができます。

```bat:
set /a x=(1+2)*3
```

シフト演算もできます。シフト演算子がリダイレクト記号として認識されないよう、式を引用符でくくります。

```bat:
set /a x="1<<2"
```

なお、小数を扱えないので、除算では小数点以下の値を切り捨てた値が商となります。また、 0 で除算することはできません。

```bat:
set /a x=1/2
set /a x=1/0
```

### インクリメント・ディクリメント

インクリメント・ディクリメント用の書式はありませんが、代入演算子の省略記法で代用します。

```bat:
set /a x+=1
set /a x-=1
set /a x*=1
set /a x/=1
```

## 文字列

### 文字列の表現

文字列は引用符でくくる必要はありません。また、値の先頭・末尾に半角空白がある場合は、文字列の一部と見なされます。

```bat:
set x=X
set x= X
set x=X X
set x=X ← 末尾に半角空白あり
```

### 文字列の結合

```bat:
set x=X
set x=%x%X
```

### 文字列の分割

`for` コマンドの文字列解析を利用します。 `tokens` に指定した値に応じて一時変数が暗黙的に追加されますが、事前に分割する数がわかっていないといけないので、使う機会は限られます。

```bat:
set x=A,B,C
for /f "tokens=1-3 delims=," %%a in ("%x%") do (
  set x[0]=%%a
  set x[1]=%%b
  set x[2]=%%c
)
```

または、以下のようにします。

```bat:
@echo off
setlocal enabledelayedexpansion
  set i=0
  set t=A,B,C
  for %%t in (%t:,= %) do (
    set x[!i!]=%%t
    set /a i+=1
  )
  echo %x[0]%
  echo %x[1]%
  echo %x[2]%
endlocal
```

### 文字列の長さ

文字列長を取得するコマンドはありません。そのため、以下のようにして求めます。

```bat:
@echo off
setlocal
  set i=0
  set t=%~1
  if "%t%" == "" exit /b 0
  :BOL
    set t=%t:~1%
    set /a i+=1
  if not "%t%" == "" goto BOL
  exit /b %i%
endlocal
```

### 文字列の抽出

指定した範囲の文字列を抽出します。文字列の先頭は 1 ではなく 0 です。

```
set x=1234567890

:: 文字列の先頭から数えて 3 文字めから最後までの文字列を抽出
:: 4567890
echo %x:~3%

:: 文字列の末尾から数えて m 文字めから最後までの文字列を抽出
:: 890
echo %x:~-3%

:: 文字列の先頭から数えて m 文字めから最後までの文字列を抽出し、
:: その文字列の先頭から数えて n 文字を抽出
:: 45
echo %x:~3,2%

:: 文字列の末尾から数えて m 文字めから最後までの文字列を抽出し、
:: その文字列の先頭から指定した n 文字を抽出
:: 89
echo %x:~-3,2%

:: 文字列の先頭から数えて m 文字めから最後までの文字列を抽出し、
:: その文字列の末尾から指定した n 文字を削除
:: 45678
echo %x:~3,-2%

:: 文字列の末尾から数えて m 文字めから最後までの文字列を抽出し、
:: その文字列の末尾から指定した n 文字を削除
:: 8
echo %x:~-3,-2%
```

### 文字列の検索

文字列を検索して見つかった位置を求めるコマンドはありませんが、`findstr` コマンドを利用することで指定した文字列が含まれているか確かめることができます。

```bat:
(echo あいうえお) | findstr /l "う" > NUL
if %ERRORLEVEL% equ 0 (
  echo 文字列が見つかりました。
) else (
  echo 文字列が見つかりません。
)
```

### 文字列の置換

指定した文字列に置換します。

```bat:
set x=xxxxxxxx
set x=%x:x=X%
```

## 配列

### 変数の宣言と代入

配列はありませんが、変数によって配列を擬似的に表現することができます。

#### 一次元配列

```bat:
@echo off
setlocal enabledelayedexpansion
  for /l %%i in (0, 1, 9) do (
    set x[%%i]=%i
  )
  for /l %%i in (0, 1, 9) do (
    echo !x[%%i]!
  )
endlocal
```

#### 二次元配列

```bat:
@echo off
setlocal enabledelayedexpansion
  for /l %%i in (0, 1, 9) do (
    for /l %%j in (0, 1, 9) do (
      set /a x[%%i][%%j]=%%i*%%j
    )
  )
  for /l %%i in (0, 1, 9) do (
    for /l %%j in (0, 1, 9) do (
      echo !x[%%i][%%j]!
    )
  )
endlocal
```

### 要素の参照

要素の値を参照します。

```bat:
echo %x[0]%
```

### 要素の個数

要素の個数を求めるには `set` コマンドを利用します。

```bat:
echo %x[0]%
for /f "" %%i in ('set x ^| findstr /r x\[.*\]') do (
  set /a i+=1
)
echo %i%
```

## 連想配列

### 変数の宣言と代入

連想配列はありませんが、変数によって連想配列を擬似的に表現することができます。

```bat:
for %k in (A B C) do (
  set x["%k"]=%k
)
```

### 要素の参照

要素の値を参照します。

```bat:
echo %x["A"]%
```

### 要素の個数

要素の個数を求めるには `set` コマンドを利用します。

```bat:
for /f "" %%i in ('set x ^| findstr /r x\[.*\]') do (
  set /a i+=1
)
echo %i%
```

## 制御文

### 条件分岐

条件判断によって処理を分岐します。`if` コマンドは一つのブロックとして扱われるので、丸カッコの中で変数を使用した場合、すべての変数が展開されてから処理が実行されます。丸カッコの中で変数の値を変更する時は遅延環境変数展開という機能を利用する必要があります。

```bat:
if 条件 (
  コマンド
)
```

```bat:
if 条件 (
  コマンド
) else (
  コマンド
)
```

#### 否定

```bat:
if not 条件 (
  コマンド
)
```

#### 数値の比較

比較演算子は以下の 6種類が利用できます。

| 演算子              | 説明 |
|:--------------------|:----:|
| equ (EQUal)         |  ==  |
| neq (Not EQual)     |  !=  |
| lss (LeSS than)     |  <   |
| leq (Less EQual)    |  <=  |
| gtr (GreaTeR than)  |  >   |
| geq (Greater EQual) |  >=  |

```bat:
set x=0
if %x% equ 0 (
  echo 変数 xの値は 0です。
)
```

#### 文字列の比較

文字列を引用符でくくる必要はありませんが、半角空白を含む文字列や空文字の場合は必要です。しかし、文字列に引用符が含まれる場合は意図したとおりに動作しません。

```bat:
set x=A
if "%x%" == "A" (
  echo 変数 x の値は A です。
)
```

`if` コマンドに `/i` オプションを指定すると、大文字と小文字を区別せずに比較します。

```bat:
set x=a
if /i "%x%" == "A" (
  echo 変数 x の値は A です。
)
```

#### 終了ステータスの確認

終了ステータスの確認には二つの書式があります。

前者はキーワードですが、後者は環境変数なので変数展開した上で数値として比較します。

```bat:
if errorlevel 0 (
  コマンド
)
```

```bat:
if %ERRORLEVEL% equ 0 (
  コマンド
)
```

#### ファイル存在の確認

文字列を引用符でくくる必要はありませんが、文字列に半角空白が含まれる場合は必要です。

```bat:
if exist "パス文字列" (
  echo ファイルが見つかりました。
) else (
  echo ファイルが見つかりません。
)
```

#### ファイル存在の確認

文字列を引用符でくくる必要はありませんが、文字列に半角空白が含まれる場合は必要です。

```bat:
if exist "パス文字列" (
  echo ファイルが見つかりました。
) else (
  echo ファイルが見つかりません。
)
```

#### 変数宣言の確認

すでに変数が宣言されているか確認することができます。変数名は引用符でくくりません。くくると引用符も変数名の一部と見なされます。

```bat:
if defined 変数名 (
  echo 変数は宣言されています。
) else (
  echo 変数は宣言されていません。
)
```

### 無条件分岐

`goto` コマンドを利用して指定したラベルへ移動することができます。`if` コマンドと組み合わせて使用したり、関数から呼び出し先に戻る時に使用します。`goto` コマンドの後に指定するラベル名には `:`（コロン）を付ける必要はありません。

```bat:
コマンド
if %ERRORLEVEL% equ 1 goto ラベル (1)
if %ERRORLEVEL% equ 2 goto ラベル (2)
exit

:ラベル (1)
  コマンド
  exit

:ラベル (2)
  コマンド
  exit
```

なお、ファイルの終端を意味する `:EOF`（End Of File）という特殊なラベルがあります。これについては関数の説明を参照してください。

### 繰り返し（ループ）

同じ処理を繰り返し実行します。繰り返しにはラベルを利用した書式と `for` コマンドを利用した書式の二つがあります。

```bat:
:ラベル名
  コマンド
if 条件 goto ラベル名

for 変数 in (条件) do (
  コマンド
```

`for` コマンドには多くの機能が実装されています。よく使われるのは一般的なループ（`/l` オプション）と値を列挙するループですが、他にも文字列操作（`/f` オプション）や複数のフォルダー間を移動しながら再帰的に処理を実行する（`/r` オプション）など、いろいろな用途に利用することができます。

#### 一般的なループ

```bat:
for /l %%i in (0, 1, 9) do (
  echo %%i
)

for /l %%i in (9, -1, 0) do (
  echo %%i
)
```

#### 値を列挙するループ

半角空白を区切り文字として一時変数に一つずつ値を代入します。

```bat:
set x=X Y Z
for %%i in (%x%) do (
  echo %%i
)
```

#### 文字列操作

文字列操作の説明を参照してください。

#### ファイルから一行ずつ読み込む

```bat:
@echo off
(
  (echo A B C D E F G H I J K L M) ^
& (echo N O P Q R S T U V W X Y Z)
) > X.txt

for /f "tokens=*" %%i in (X.txt) do (
  echo %%i
)

del X.txt
```

#### フォルダーを移動しながら処理を実行

```bat:
for /r %%i in (.) do (
  echo %%i
)
```

#### 無限ループ

```bat:
:BOL
  コマンド
goto BOL

for /l %%i in (0, 0, 0) do (
  コマンド
)
```

推奨できませんが、無限ループを利用して以下のように書くこともできます。

```bat:
for /l %%i in (0, 0, 0) do (
  コマンド && goto BREAK
  ping -n 3 127.0.0.1 > NUL
)
:BREAK
```

## 関数

### サブルーチンと関数

関数はありませんが、サブルーチンと `call` コマンドを利用することで関数を擬似的に表現することができます。

`goto` コマンドは指定されたラベルに移動するだけですが、`call` コマンドは別のコンテキストで処理が実行されるため、引数を渡したり、終了ステータスを返すことができます。

`call` コマンドを利用したサブルーチンは、`goto` コマンドを利用したものよりもより関数に近い機能を持つので、ここではあえて関数と呼ぶことにします。

### 関数の定義

関数を定義するにはラベルと `setlocal` コマンドと `endlocal` コマンドを組み合わせて利用します。`setlocal` コマンドと `endlocal` コマンドで変数のスコープを設定し、`:EOF`（End Of File）という特殊なラベルを利用することで関数の呼び出し先に戻ります。

```bat:
:ラベル名
  setlocal
    処理
  endlocal
goto :EOF
```

### 関数の呼び出し

`call` コマンドを利用して呼び出します。

```bat:
call :ラベル名
```

または、処理を別のファイルに書いておき、それを呼び出すこともできます。

```bat:
call ファイル名
```

関数に引数を渡すにはラベルの後に指定します。

```bat:
call :ラベル名 引数
```

引数は半角空白や `,`（カンマ）や `;`（セミコロン）で区切って複数渡すことができます。

```bat:
call :ラベル名 引数 (1) 引数 (2)
call :ラベル名 引数 (1),引数 (2)
call :ラベル名 引数 (1);引数 (2)
```

### 引数の参照

引数は `%番号` で参照することができます。引数が引用符付きで渡された場合、`%` と番号の間に `~` を追加することで、引用符を削除することができます。半角空白を含む文字列や空文字列を渡す時に利用します。

```bat:
@echo off
  setlocal
    call :X "X"
  endlocal
goto :EOF

:X
  setlocal
    echo %1
    echo %~1
  endlocal
goto :EOF
```

### 戻り値の返却

#### 終了ステータス

終了ステータスを返すには `exit` コマンドを利用します。

```bat:
@echo off
  setlocal
    call :X "X"
    echo %ERRORLEVEL%
  endlocal
goto :EOF

:X
  setlocal
    if not defined %~1 (
      exit /b 1
    ) else (
      exit /b 0
    )
  endlocal
goto :EOF
```

#### 数値・文字列

戻り値を呼び出し先に返すこともできますが、少し特殊な書式になります。引数に**戻り値をセットする変数名**を渡し、`endlocal` コマンドの後に `&`（アンパサンド）を書きます。最後に変数名を利用して値をセットします。

```bat:
@echo off
  setlocal
    call :X "X" x
  endlocal
goto :EOF

:X
  setlocal
    set s=%~1
    set s=%~1X
  endlocal & set %2=%s%
goto :EOF
```

これは `endlocal` コマンドの行を実行する際、まず最初に変数展開が行われる性質を利用しています。これにより、`setlocal` コマンドと `endlocal` コマンドで設定したスコープの外であっても、関数内で処理した値を関数外に渡すことができます。

## ファイル入出力

### 標準出力

コマンドが出力するメッセージをファイルとして保存したい場合は `>`（リダイレクト演算子）を利用します。

```bat:
コマンド > ファイル名
```

コマンド実行時にそのコマンドが標準出力にメッセージを出力していれば、指定したファイルにメッセージが書き込まれます。

ファイルにメッセージを追記するにはリダイレクト演算子を重ねて指定します。

```bat:
コマンド >> ファイル名
```

### 標準エラー出力

コマンド実行時にエラーが発生した場合、そのコマンドが標準エラー出力にメッセージを出力していれば、指定したファイルにメッセージが書き込まれます。

```bat:
コマンド 2> ファイル名
```

また、メッセージが標準出力と標準エラー出力に出力されている場合、両方を同じファイルに出力することもできます。

```bat:
コマンド > ファイル名 2> ファイル名
```

または、

```bat:
コマンド > ファイル名 2>&1
```

`&1` は標準出力の出力先を意味します。標準エラー出力のデフォルトの出力先はコンソールですが、上の例ではこれを標準出力と同じ出力先に変更しています。標準出力の出力先にはファイルが指定されているので、標準エラー出力の出力先もファイルとなります。

### 標準入力

標準入力を通じてファイルの内容を一行ずつ読み込み、コマンドに渡します。ただし、コマンドが標準入力からの入力に対応している場合に限ります。

```bat:
コマンド < ファイル名
```

これにより、コマンドの実行結果をファイルに出力しておき、それを標準入力を通じて別のコマンドで読み込んで処理するということもできます。

しかしいちいちファイルを作成しなくても、`|`（パイプ演算子）を利用すれば、あるコマンドが標準出力に出力するメッセージを別のコマンドの標準入力に直接渡すことができます。

```bat:
コマンド (1) | コマンド (2)
```

## 正規表現

`findstr` コマンドのヘルプを参照してください。

## 糖衣構文

複数のコマンドを一行にまとめて書いたり、可読性を上げるために使用します。

#### ()

`()`（グループ演算子）でくくることで、複数のコマンドをまとめることができます。

```bat:
(echo 12345) >  X.txt
(echo 67890) >> X.txt
↓
(
  echo 12345
  echo 67890
) > X.txt
```

ただし、別のコンテキストで実行されることがあるため、丸カッコの中で変数に値を代入しても、その外からは変更された値を参照できない場合があります。

```bat:
C:\>(set x=1) & echo %x%
```

#### &&

`&&` の前のコマンドの終了ステータスが 0 の場合、後のコマンドを実行します。

```bat:
コマンド (1)
if %ERRORLEVEL% equ 0 (
  コマンド (2)
)
↓
コマンド (1) && コマンド (2)
```

#### ||

`||` の前のコマンドの終了ステータスが 0 以外の場合、後のコマンドを実行します。

```bat:
コマンド (1)
if %ERRORLEVEL% neq 0 (
  コマンド (2)
)
↓
コマンド (1) || コマンド (2)
```

また、`&&` と組み合わせて、条件分岐を以下のように書くこともできます。

```bat:
コマンド
if %ERRORLEVEL% equ 0 (
  コマンド (1)
) else (
  コマンド (2)
)
↓
コマンド && (コマンド (1)) || (コマンド (2))
```

#### &

`&` の前のコマンドを実行した後、後のコマンドを実行します。`&&` と異なり、前のコマンドの終了ステータスに左右されません。

```bat:
コマンド (1)
コマンド (2)
↓
コマンド (1) & コマンド (2)
```

#### if コマンド

```bat:
if 条件 (
  コマンド
)
↓
if 条件 (コマンド)
```

または、

```bat:
if 条件 (
  コマンド (1)
) else (
  コマンド (2)
)
↓
if 条件 (コマンド (1)) else (コマンド (2))
```

丸カッコの中で実行するコマンドが一つしかなければ、丸カッコを省略することもできます。

```bat:
if 条件 コマンド
```

#### for コマンド

`if` コマンドと同様に省略することができます。

```bat:
for 変数 in (条件) do (
  コマンド
)
↓
for 変数 in (条件) do (コマンド)
for 変数 in (条件) do コマンド
```

#### set コマンド

数値の代入のみ、`,`（カンマ演算子）で区切って宣言することができます。

```bat:
set /a 変数 (1)=値 (1)
set /a 変数 (2)=値 (2)
↓
set /a 変数 (1)=値 (1),変数 (2)=値 (2)
```

## 注意

* コマンドプロンプトは Windows のバージョンアップとともに機能が拡張されてきました。そのため、最新バージョンの Windows で動作するものが古いバージョンの Windows でも動作するとは限りません。移植性は高くないので注意してください。

* バッチファイルは C 言語のようなコンパイル済みのバイナリファイルと比べ、実行速度は遅いです。また、 Windows 以外のシステムでは使用できないため、可搬性もありません。

* バッチファイルの実行を一時停止してファイルを修正・保存した場合、一時停止を解除した後の挙動は不定です。

* `if` コマンドや `for` コマンドの丸カッコの中で複雑な処理を行おうとすると、意図したとおりに動作しないことがあります。

* 以下のバッチファイルを作成して実行すると、

```bat:sample.bat
call %0
```

スタックの 90% を使用した時点で処理が中断されます。

```
****** B A T C H   R E C U R S I O N  exceeds STACK limits ******
Recursion Count=1240, Stack Usage=90 percent                     
******      B A T C H   PROCESSING IS   A B O R T E D      ******
```

なお、`call` コマンドを利用しない場合は無限ループになります。

```bat:sample.bat
%0
```

## 参考

* 「Windows XP/2000コマンドプロンプト ポケットリファレンス」（天野司，技術評論社）
* [コマンドシェルの概要](https://web.archive.org/web/20100109083452/http://technet.microsoft.com/ja-jp/library/cc737438(WS.10).aspx)
* [Windows 2000コマンドライン徹底活用](http://www.atmarkit.co.jp/fwin2k/operation/command001/command1.html)
* [Batch Function Library for Windows](http://www.commandline.co.uk/)
* [それはそれ。これはこれ。](http://d.hatena.ne.jp/otn/)
* [DOS プロンプト活用相談室 LOG](http://fpcu.on.coocan.jp/dosvcmd/bbs/log/)
* [どう書く？.org](https://github.com/nacyot/doukaku_parser)
* [cigi の日記](http://d.hatena.ne.jp/cigi/searchdiary?word=%2A%5BBAT%5D)
* [Guide to Windows Batch Scripting](http://steve-jansen.github.io/guides/windows-batch-scripting/)
* [Windows Script Programming](http://scripting.cocolog-nifty.com/blog/)
* [Tech TIPS](http://www.atmarkit.co.jp/ait/articles/1506/26/news026.html)
* [ひしだま's ホームページ](http://www.ne.jp/asahi/hishidama/home/tech/windows/bat.html)
* [(ss64)](https://ss64.com/nt/)
* [DOS Batch](http://www.dostips.com/DtTutoFunctions.php)
* [バッチファイルの概要](http://takeno.iee.niit.ac.jp/~shige/misc/script/bat1/bat1.html)
* [いざというときに役立つ MS-DOS](http://www.geocities.co.jp/Bookend-Hemingway/4963/column/dos/backno.html)
* [Windows の findstr で正規表現を検索する](http://www.atmarkit.co.jp/ait/articles/0412/18/news018.html)
* [どーでもえぐぜ](http://doudemoexe.com/Batch/)
* [Information on batch files](https://www.computerhope.com/batch.htm)
* [Batch file](https://en.wikipedia.org/wiki/Batch_file)
* [バッチ職人になろう](http://language-and-engineering.hatenablog.jp/entry/20110904/p1)
* [ERRORLEVEL についてのメモ](http://d.hatena.ne.jp/simply-k/20100812/1281653517)
* [全般／構文解析](http://otnx.jp/CMD/%C1%B4%C8%CC/%B9%BD%CA%B8%B2%F2%C0%CF/)
* [is Bug Ready?](http://d.hatena.ne.jp/ladybug/20090530#p1)
* [Batch files](http://www.robvanderwoude.com/batchfiles.php)
* [コマンドプロンプトのエスケープ仕様](http://up-cat.net/%25A5%25B3%25A5%25DE%25A5%25F3%25A5%25C9%25A5%25D7%25A5%25ED%25A5%25F3%25A5%25D7%25A5%25C8%25A4%25CE%25A5%25A8%25A5%25B9%25A5%25B1%25A1%25BC%25A5%25D7%25BB%25C5%25CD%25CD.html)

## 付録

### サンプル

カレンダーを表示するバッチファイルです。 cal.batという名前でファイルを保存し、コマンドプロンプトから以下のように実行してください。

```
C:\>cal 2 2010
2010/ 2
Su Mo Tu We Th Fr Sa
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28
```

```bat:cal.bat
@echo off
  setlocal enabledelayedexpansion
    set d= 030101001010
    set n=0
    set t=
    set w=0
    
    (echo %1%2) | findstr /r "[^0-9]." > NUL
    if %ERRORLEVEL% equ 0 (
      echo Usage: %~n0 MONTH YEAR
      exit /b 1
    )
    
    if %1 lss  1 (
      echo %~n0: illegal month value: use 1-12
      exit /b 1
    )
    if %1 gtr 12 (
      echo %~n0: illegal month value: use 1-12
      exit /b 1
    )
    
    if %2 lss    1 (
      echo %~n0: illegal year value: use 1-9999
      exit /b 1
    )
    if %2 gtr 9999 (
      echo %~n0: illegal year value: use 1-9999
      exit /b 1
    )
    
    :: 指定された日の曜日を取得
    call :Z %2 %1 1 w
    
    :: 指定された月の日数を取得
    set /a d=31-!d:~%1,1!
    if %1 equ 2 (call :is_leap_year %2 || set /a d+=1)
    
    :: カレンダーを表示
    if %1 lss 10 (
      echo %2/ %1
    ) else (
      echo %2/%1
    )
    echo Su Mo Tu We Th Fr Sa
    for /l %%i in (1, 1, %w%) do (set t=!t!   )
    for /l %%d in (1, 1, %d%) do (
      if %%d lss 10 (set t=!t! )
      set t=!t!%%d
      call :Z %2 %1 %%d n
      if !n! equ 6 (echo !t! & set t=) else (set t=!t! )
    )
    if not "%t%" == "" echo %t%
    echo.
  endlocal
goto :EOF

:is_leap_year
  setlocal
    set n=0
    
    set /a n=%1%%400
    if %n% equ 0 exit /b 1
    
    set /a n=%1%%100
    if %n% equ 0 exit /b 0
    
    set /a n=%1%%4
    if %n% equ 0 exit /b 1
    
    exit /b 0
  endlocal
goto :EOF

:: ツェラーの公式
:Z
  setlocal
    set y=%1
    set m=%2
    set w=0
    
    if %m% leq 2 (
      set /a y-=1
      set /a m+=12
    )
    
    set /a w=(5*%y%/4-%y%/100+%y%/400+(26*%m%+16)/10+%3)%%7
  endlocal & set %4=%w%
goto :EOF
```

### 組み込みコマンド

コマンドプロンプト（cmd.exe）自体に組み込まれたコマンドです。

```
assoc        copy         exit         md           prompt       set          type
break        date         fcfind       mkdir        pushd        setlocal     ver
call         del          for          mklink       rd           shift        verify
cd           dir          ftype        move         rem          start        vol
chdir        echo         goto         path         ren          subst        
cls          endlocal     graftabl     pause        rename       time         
color        erase        if           popd         rmdir        title        
```