← README に戻る
目次
- 変数と展開
- 引数と
%~ 修飾子
- エスケープ
- 条件分岐
if
- 繰り返し
for
- 文字列操作
- リダイレクトと終了コード
- よく使うコマンド
変数と展開
代入
| 書き方 | 意味 | 備考 |
set VAR=値 | 代入 | = の前後に空白を入れない。set VAR = 値 は変数名が VAR 、値が 値 になる |
set "VAR=値" | 代入(推奨形) | 値の末尾に空白が付かない。値に & や | を含められる(ただし読み出しは !VAR! で行う。下の注意を参照) |
set /a VAR=1+2 | 数値計算して代入 | /a のときだけ値が数値として扱われる。% は剰余になる(バッチ内では %%) |
set /p VAR=入力: | キーボード入力を代入 | 入力待ちになる。無人実行するバッチでは使わない |
set "VAR=" | 変数を削除 | 空文字の代入ではなく削除。if defined が偽になる |
展開(読み出し)
| 書き方 | 展開されるタイミング | 使う場面 |
%VAR% | その行が読み込まれた時点(実行前) | 通常。ただし括弧ブロックの中では値が古いままになる。展開後の行がもう一度コマンドとして読み直される |
!VAR! | その行が実行される直前 | for や if の括弧内。setlocal enabledelayedexpansion が必要。展開結果は読み直されないため記号を含む値でも安全 |
%%f | for の各回 | for のループ変数。バッチ内は %%、コマンドプロンプトに直接打つときは % 1つ |
括弧の中では !VAR! を使う。for や if の ( 〜 ) は、中に入る前に全体が1回だけ文字列展開されます。ループごとに変わる値を %VAR% で読むと、全周にわたって同じ値になります。
記号を含む値も !VAR! で読む。set "MSG=Hello & World" の代入は成功しますが、echo %MSG% は展開後の echo Hello & World という行が読み直され、& がコマンド区切りとして働いて壊れます。echo !MSG! なら展開結果が読み直されないため正しく表示されます。
スコープ
| 書き方 | 意味 |
setlocal | これ以降の変数変更をこのスクリプト内に閉じる。書かないと呼び出し元の環境変数を書き換える |
setlocal enabledelayedexpansion | 上に加えて !VAR! を有効にする。実質これが標準形 |
endlocal | 変更を破棄して元に戻す。スクリプト終了時に自動で行われる |
endlocal & set "X=%X%" | endlocal を越えて値を1つだけ持ち出す定型 |
引数と %~ 修飾子
引数の受け取り
| 書き方 | 意味 |
%0 | 実行されたバッチ自身のパス |
%1 … %9 | 1〜9番目の引数 |
%* | すべての引数をまとめた文字列 |
shift | 引数を1つずつずらす。10個以上の引数を扱うときに使う |
%~1 | 1番目の引数から前後のダブルクォートを外したもの |
%~ 修飾子(%0 と %1〜、for の変数に使える)
ここでは C:\work\data\input.txt が渡された場合の展開結果を示します。
| 書き方 | 意味 | 展開結果 |
%~1 | クォートを外す | C:\work\data\input.txt |
%~f1 | フルパスにする | C:\work\data\input.txt |
%~d1 | ドライブ | C: |
%~p1 | パス部分 | \work\data\ |
%~dp1 | ドライブ+パス | C:\work\data\ |
%~n1 | 拡張子なしのファイル名 | input |
%~x1 | 拡張子 | .txt |
%~nx1 | ファイル名+拡張子 | input.txt |
%~s1 | 8.3形式の短いパス | 空白を含むパスの回避に使う |
%~a1 | ファイル属性 | --a------ |
%~t1 | 更新日時 | 2026/08/25 10:30 |
%~z1 | ファイルサイズ | 1024 |
自分の場所を指す定型
| 書き方 | 意味 | 注意 |
%~dp0 | このバッチがあるフォルダ(末尾に \ 付き) | "%~dp0file.txt" と連結する。"%~dp0\file.txt" は \ が二重になる |
%~nx0 | このバッチのファイル名 | 使い方(usage)表示に使う |
pushd "%~dp0" | このバッチの場所へ移動 | UNC パスでも動く。戻すときは popd |
エスケープ
| 文字 | そのまま書くと | エスケープ | 備考 |
% | 変数展開として解釈される | %% | バッチファイル内のみ。プロンプトに直接打つときは % 1つ |
^ | 次の1文字のエスケープ記号 | ^^ | 行末に置くと行継続になる |
& | コマンドの区切り | ^& | " で囲んだ中なら不要 |
| | パイプ | ^| | 同上 |
> < | リダイレクト | ^> ^< | 同上 |
( ) | ブロックの区切り | ^( ^) | ブロック内では特に必要になる |
! | 遅延展開が有効なとき変数として解釈される | ^^! | ^ が2つ必要。^! では展開されてしまう。遅延展開が無効ならエスケープ不要 |
" | 文字列の区切り | — | エスケープできない。数を偶数に保つのが基本 |
迷ったら文字列全体を " で囲む。& | > < ( ) はダブルクォートの内側では特別扱いされません。^ を1文字ずつ付けるより事故が少なくなります。ただし % と ! はクォートの中でも展開されるため、これだけは %% / ^^! が必要です。
! だけ ^ が2つ必要な理由
1行は「% の展開 → ^ の処理 → ! の展開」という順に解釈されます。! の展開が ^ の処理より後にあるため、^! と書くと ^ が先に消費されて ! だけが残り、そのあと変数として展開されてしまいます。
@echo off
setlocal enabledelayedexpansion
set "MSG=VALUE"
echo 1: ^!MSG^!
echo 2: ^^!MSG^^!
1: VALUE
2: !MSG!
^^ が ^ 1つに減り、その ^ が ! の展開を止めます。! をリテラルで出したいだけなら、その箇所を setlocal disabledelayedexpansion で囲んで遅延展開を切るほうが読みやすくなります。
行継続
rem 長いコマンドを複数行に分ける(行末に ^ 、次の行は続きとして扱われる)
robocopy "C:\src" "C:\dst" ^
/E /R:1 /W:1 ^
/LOG:"%~dp0robocopy.log"
要注意^ の後ろに空白があると行継続として機能しません。行末は ^ で終わらせます。
条件分岐 if
基本形
| 書き方 | 意味 |
if "%A%"=="x" ( … ) | 文字列の一致。両辺を " で囲むのが定型(空のときに構文エラーになるのを防ぐ) |
if /i "%A%"=="x" ( … ) | 大文字小文字を区別しない比較 |
if not "%A%"=="x" ( … ) | 否定 |
if defined A ( … ) | 変数が定義されているか。% で囲まない |
if exist "path" ( … ) | ファイル・フォルダの存在。フォルダを確かめたいときは "path\" と末尾に \ を付ける |
if errorlevel 1 ( … ) | 直前の終了コードが 1以上なら真(「1と等しい」ではない) |
if %N% GEQ 10 ( … ) | 数値比較 |
数値比較の演算子
| 演算子 | 意味 | 他言語 |
EQU | 等しい | == |
NEQ | 等しくない | != |
LSS | より小さい | < |
LEQ | 以下 | <= |
GTR | より大きい | > |
GEQ | 以上 | >= |
else の書き方
rem 正しい: ) と else と ( を同じ行に置く
if "%A%"=="x" (
echo A は x
) else (
echo A は x ではない
)
構文エラー) と else を別の行に分けると動きません。if は1つの論理行として解析されるためです。
if の中で %errorlevel% は使えない。ブロック内の %errorlevel% はブロックに入る前の値に固定されています。ブロック内で更新後の値を見るには !errorlevel! か if errorlevel 1 を使います。
繰り返し for
4つの形
| 形 | 回すもの | 例 |
| 無印 | ファイル名・空白区切りの文字列 | for %%f in (*.txt) do echo %%f |
/l | 数値の範囲(開始,増分,終了) | for /l %%i in (1,1,5) do echo %%i |
/f | ファイルの各行・文字列・コマンド出力 | for /f "delims=" %%l in (a.txt) do echo %%l |
/r | サブフォルダを含むファイル | for /r "C:\work" %%f in (*.log) do echo %%f |
/d | フォルダのみ | for /d %%d in (*) do echo %%d |
/f のオプション
| オプション | 意味 |
delims=, | 区切り文字を指定(既定は空白とタブ)。delims= と空にすると行全体を1つとして扱う |
tokens=1,3 | 取り出す列の番号。tokens=1,* で「1列目」と「残り全部」 |
skip=1 | 先頭のn行を飛ばす(ヘッダ行の読み飛ばし) |
eol=; | この文字で始まる行を無視する(既定は ;) |
usebackq | 引用符の意味を変える。空白を含むファイル名を読むときに必要 |
対象の指定と引用符
| 書き方 | 回す対象 |
in (a.txt) | ファイル a.txt の各行 |
in ("文字列") | その文字列そのもの(ファイルではない) |
in ('コマンド') | コマンドの実行結果の各行 |
in ("C:\a b\c.txt") + usebackq | 空白を含むパスのファイルの各行 |
rem 空白を含むパスのファイルを1行ずつ読む
for /f "usebackq delims=" %%l in ("%~dp0data file.txt") do (
echo 行: %%l
)
rem コマンドの出力を読む(usebackq のときはバッククォート)
for /f "usebackq tokens=1,2 delims=," %%a in (`type list.csv`) do (
echo 1列目=%%a 2列目=%%b
)
tokens を複数指定すると変数は自動で増える。tokens=1,2,3 で %%a を指定した場合、2列目は %%b、3列目は %%c になります。宣言は不要で、アルファベット順に割り当てられます。
ループの脱出
break はありません。goto でループの外のラベルへ飛ぶか、フラグ変数で以降の処理をスキップします。
for %%f in (*.txt) do (
if "%%~nf"=="target" goto :found
)
echo 見つかりませんでした
goto :eof
:found
echo 見つかりました
文字列操作
いずれも %VAR% 形式の変数にしか使えません。引数 %1 や for の %%f に直接は使えないため、いったん set "V=%~1" で変数に入れます。
| 書き方 | 意味 | 例(V=abcdefg) |
%V:~0,3% | 0文字目から3文字 | abc |
%V:~3% | 3文字目から末尾まで | defg |
%V:~-2% | 末尾から2文字 | fg |
%V:~0,-2% | 末尾2文字を除いた残り | abcde |
%V:abc=X% | 置換 | Xdefg |
%V:abc=% | 削除(空文字に置換) | defg |
よく使う組み合わせ
| やりたいこと | 書き方 |
| 文字列を含むか判定 | if not "%V:abc=%"=="%V%" ( 含む ) |
末尾の \ を取り除く | if "%V:~-1%"=="\" set "V=%V:~0,-1%" |
| パスの区切りを置換 | set "V=%V:\=/%" |
| 大文字小文字を無視して置換 | 不可。for /f と外部コマンドを使う |
置換・部分取得は !V! 形式でも書ける。ループ内で使う場合は !V:~0,3! のように ! で囲みます。ただし値そのものに = や : が含まれると解釈が崩れるため、この記法で扱うのはパスや識別子程度にとどめるのが安全です。
リダイレクトと終了コード
リダイレクト
| 書き方 | 意味 |
> file | 標準出力をファイルへ(上書き) |
>> file | 標準出力をファイルへ(追記) |
2> file | 標準エラーをファイルへ |
> file 2>&1 | 標準出力と標準エラーをまとめてファイルへ |
> nul | 出力を破棄する |
2> nul | エラー出力だけ破棄する |
< file | ファイルを標準入力として渡す |
cmd1 | cmd2 | cmd1 の出力を cmd2 の入力へ |
要注意2>&1 は「その時点の標準出力と同じ先」を意味するため、順序が変わると結果が変わります。> file 2>&1 は両方がファイルへ、2>&1 > file は標準出力だけがファイルへ行き、エラーは画面に残ります。
終了コード
| 書き方 | 意味 |
%errorlevel% | 直前のコマンドの終了コード。0 が成功 |
if errorlevel 1 | 1以上(=失敗)なら真 |
cmd && 次 | cmd が成功したときだけ次を実行 |
cmd || 次 | cmd が失敗したときだけ次を実行 |
exit /b n | このバッチを終了コード n で終える |
exit n | cmd.exe そのものを終える(呼び出し元も閉じる) |
goto :eof | サブルーチンから戻る / スクリプトの末尾へ飛ぶ |
rem 失敗したら中断する定型
copy "%SRC%" "%DST%" || (
echo コピーに失敗しました
exit /b 1
)
サブルーチン
call :log "処理を開始します"
call :log "処理が完了しました"
goto :eof
:log
echo [%DATE% %TIME%] %~1
goto :eof
call を付けずに :log へ goto すると、そこから戻ってきません。
よく使うコマンド
ファイル・フォルダ
| コマンド | 用途 | 覚えておくオプション |
copy | ファイルのコピー | /y 上書き確認なし |
xcopy | フォルダごとコピー | /e /i /y |
robocopy | 大量・差分コピー | /e /r:1 /w:1。終了コードが 0 以外でも成功のことがある |
move | 移動・リネーム | /y |
del | ファイル削除 | /q 確認なし /s サブフォルダも |
rd | フォルダ削除 | /s /q |
md | フォルダ作成 | 途中の階層も自動で作られる |
dir | 一覧 | /b 名前だけ /s 再帰 /a-d ファイルのみ |
テキスト・情報取得
| コマンド | 用途 | 備考 |
type | ファイルの内容を表示 | 複数ファイルの連結にも使える |
find | 文字列の検索 | " で囲む必要がある。/c で件数、/v で否定 |
findstr | 正規表現の検索 | /i 大小無視 /r 正規表現 /c:"..." 語句指定 |
where | 実行ファイルの場所を探す | 存在確認にも使える(見つからないと終了コードが 1) |
tasklist | プロセス一覧 | /fi "imagename eq x.exe" |
chcp | コードページの確認・変更 | 日本語環境は 932。65001(UTF-8)への変更は副作用があるため安易に使わない |
制御・その他
| コマンド | 用途 | 備考 |
@echo off | 実行するコマンド自体の表示を止める | 1行目に書く。先頭の @ はこの行自身を隠すため |
rem | コメント | 括弧の中でも安全。:: はラベルなので括弧内では使えない |
pause | キー入力を待つ | ダブルクリック実行で結果を読ませたいときに末尾へ |
timeout /t 5 | 5秒待つ | /nobreak でキー入力による中断を防ぐ |
start "" | 別プロセスとして起動 | 第1引数はウィンドウタイトル扱いなので "" を置く |
call other.cmd | 別のバッチを呼んで戻る | call なしでは戻ってこない |
pushd / popd | 移動して戻る | UNC パスにも対応する |
title | ウィンドウタイトルを設定 | 長時間動くバッチで進捗を示すのに使える |
コマンドのヘルプは コマンド /? で読める。for /? や set /? は、この早見表より詳しい説明を出します。出力が長いので for /? | more やファイルへのリダイレクトと併せて使ってください。