バッチファイルで「フォルダ内のファイルを一括処理したい」「1から10まで繰り返したい」「CSVを1行ずつ読み込みたい」といった場面で活躍するのがFOR文です。しかし、コマンドプロンプトで使う書き方とバッチファイル内での書き方が異なったり、オプションが多かったりで「よくわからない」と感じる方も多いのではないでしょうか。
この記事では、FOR文の5種類の構文を基本から実務パターンまでわかりやすく解説します。コピーしてすぐ使えるサンプルコードも豊富に用意しています。
この記事で学べること
- FOR文の5種類の構文(基本・/L・/F・/D・/R)の使い方
- コマンドプロンプトとバッチファイルでの%変数の書き方の違い(%i と %%i)
- ファイル一覧取得・数値ループ・CSV読み込みなどの実務パターン
- 遅延展開(
!変数!)との組み合わせ方
- FOR文でよくあるハマりポイントと解決方法
FOR文の種類と使い分け一覧
バッチファイルのFOR文には用途に応じて5種類の構文があります。まず全体像を把握しましょう。
| 構文 |
用途 |
典型的な使い方 |
| FOR %i IN (…) |
値のリストやファイルパターンに対してループ |
*.txt を一括処理する |
| FOR /L %i IN (開始,ステップ,終了) |
数値のカウンターループ |
1〜10まで繰り返す |
| FOR /F %i IN (…) |
ファイル・コマンド出力・文字列を行単位で解析 |
CSVを1行ずつ読み込む |
| FOR /D %i IN (…) |
ディレクトリ名に対してループ |
サブフォルダを一覧取得する |
| FOR /R %i IN (…) |
サブフォルダを含む再帰ループ |
全階層の .log を削除する |
コマンドプロンプトとバッチファイルでの変数の書き方の違い
FOR文を使うときに最もよくハマるのが変数の % の個数の違いです。
| 実行場所 |
書き方 |
例 |
| コマンドプロンプト(直接入力) |
%i(% ひとつ) |
FOR %i IN (a b c) DO echo %i |
| バッチファイル(.bat 内) |
%%i(% ふたつ) |
FOR %%i IN (a b c) DO echo %%i |
注意:バッチファイル内で %i(% ひとつ)と書くと、%i が引数変数として解釈されてしまい、正しく動作しません。バッチファイル内では必ず %%i と書いてください。この記事のサンプルコードはすべてバッチファイル用の %%i 表記で記載しています。
基本のFOR文:値リストとファイルパターンのループ
FOR %%変数 IN (セット) DO コマンド は、スペース区切りの値リストやワイルドカードによるファイルパターンに対してループします。
値リストをループする
for_list.bat
@echo off
chcp 932 >nul
:: 値リストをループ
FOR %%i IN (apple banana cherry) DO (
echo フルーツ: %%i
)
:: 出力:
:: フルーツ: apple
:: フルーツ: banana
:: フルーツ: cherry
pause
ワイルドカードでファイルを一括処理する
for_files.bat
@echo off
chcp 932 >nul
:: カレントフォルダの .txt ファイルをすべて処理
FOR %%f IN (*.txt) DO (
echo ファイル名: %%f
echo フルパス: %%~ff
echo ファイルサイズ: %%~zf バイト
echo ---
)
FOR文の変数には修飾子を付けることで、ファイルパスの各部分を取り出せます。
| 修飾子 |
意味 |
例(%%f が C:workdata.txt の場合) |
| %%~ff |
フルパス |
C:workdata.txt |
| %%~df |
ドライブ文字 |
C: |
| %%~pf |
フォルダパス(末尾 付き) |
C:work |
| %%~nf |
拡張子なしファイル名 |
data |
| %%~xf |
拡張子のみ |
.txt |
| %%~nxf |
ファイル名+拡張子 |
data.txt |
| %%~zf |
ファイルサイズ(バイト) |
1024 |
| %%~tf |
最終更新日時 |
2025/06/01 12:00 |
FOR /L:数値カウンターループ
FOR /L %%i IN (開始,ステップ,終了) DO は、数値を指定した範囲でインクリメント/デクリメントしながらループします。
for_l.bat
@echo off
chcp 932 >nul
:: 1 から 5 まで 1 ずつ増やす
FOR /L %%i IN (1,1,5) DO (
echo カウント: %%i
)
:: 10 から 1 まで 1 ずつ減らす(カウントダウン)
FOR /L %%i IN (10,-1,1) DO (
echo カウントダウン: %%i
)
:: 0 から 100 まで 10 ずつ増やす
FOR /L %%i IN (0,10,100) DO (
echo %%i
)
pause
実務例:連番ファイルを一括作成する
create_files.bat
@echo off
chcp 932 >nul
:: report_001.txt 〜 report_010.txt を作成
FOR /L %%i IN (1,1,10) DO (
set num=00%%i
echo レポート %%i > report_!num:~-3!.txt
echo report_!num:~-3!.txt を作成しました
)
pause
ポイント:連番のゼロ埋めには遅延展開(setlocal EnableDelayedExpansion)が必要です。!num:~-3! で文字列の末尾3文字を取り出しています。
FOR /F:ファイル・コマンド出力・文字列の解析
FOR /F は最も強力なFOR文で、テキストファイルの各行・コマンドの出力結果・文字列を1行ずつ処理できます。実務で最もよく使う構文です。
テキストファイルを1行ずつ読み込む
read_file.bat
@echo off
chcp 932 >nul
:: list.txt を1行ずつ読み込む
FOR /F "delims=" %%L IN (list.txt) DO (
echo 行: %%L
)
:: ※ "delims=" は区切り文字なし = 行全体を取得(重要)
CSVを列ごとに取り出す
read_csv.bat(data.csv の内容:田中,30,東京)
@echo off
chcp 932 >nul
:: カンマ区切りで 3列を取り出す(tokens=1,2,3 delims=,)
FOR /F "tokens=1,2,3 delims=," %%a IN (data.csv) DO (
echo 名前: %%a
echo 年齢: %%b
echo 都市: %%c
)
:: tokens=1,2,3 のとき %%a=1列目 %%b=2列目 %%c=3列目(アルファベット順)
コマンドの出力結果を変数に取り込む
get_date.bat
@echo off
chcp 932 >nul
:: コマンドの出力を変数に代入(usebackq + 波括弧でコマンドを囲む)
FOR /F "usebackq delims=" %%v IN (`ver`) DO set OS_VER=%%v
echo OSバージョン: %OS_VER%
:: ディスク空き容量を取得する例
FOR /F "tokens=3 delims= " %%s IN ('dir C: ^| findstr /C:"空き"') DO set FREE=%%s
echo Cドライブ空き: %FREE%
pause
FOR /F のオプション(tokens・delims・skip・usebackq)
| オプション |
意味 |
例 |
| tokens=N |
取り出す列番号(1始まり)を指定。*で残り全体 |
tokens=1,2 |
| delims=文字 |
区切り文字を指定。デフォルトはスペース/タブ |
delims=, |
| skip=N |
先頭N行をスキップ(ヘッダー行スキップに便利) |
skip=1 |
| eol=文字 |
この文字で始まる行をスキップ(デフォルトは;) |
eol=# |
| usebackq |
バッククォート(`)でコマンド実行、ダブルクォートでファイル名指定 |
usebackq |
FOR /D:サブフォルダ名のループ
FOR /D %%d IN (パターン) DO は、ディレクトリ名に対してループします(ファイルは対象外)。
for_d.bat
@echo off
chcp 932 >nul
:: カレントフォルダのサブフォルダを一覧表示
FOR /D %%d IN (*) DO (
echo フォルダ: %%d
)
:: C:work 配下の "data_*" に一致するフォルダだけ対象
FOR /D %%d IN (C:workdata_*) DO (
echo 対象フォルダ: %%d
)
pause
FOR /R:サブフォルダを含む再帰ループ
FOR /R パス %%f IN (パターン) DO は、指定パス以下のすべてのサブフォルダを再帰的に検索してループします。ファイルの一括処理に非常に便利です。
for_r.bat
@echo off
chcp 932 >nul
:: C:work 配下のすべての .log ファイルを一覧表示
FOR /R C:work %%f IN (*.log) DO (
echo %%f
)
:: カレントフォルダ以下の .tmp ファイルをすべて削除
FOR /R %%f IN (*.tmp) DO (
echo 削除: %%f
del "%%f"
)
pause
注意:del で削除するとごみ箱に入らず完全削除されます。本番実行前に echo だけに差し替えて対象ファイルを確認してから実行してください。
ループ内で変数を更新する:遅延展開(!変数!)との組み合わせ
FOR文のループ内で SET した変数を同じループ内で参照しようとすると、期待した値にならないことがあります。これはバッチファイルのコマンドブロック展開の仕組みによるもので、解決にはsetlocal EnableDelayedExpansionと!変数名!構文が必要です。
delayed_expansion.bat
@echo off
chcp 932 >nul
setlocal EnableDelayedExpansion
set COUNT=0
FOR /L %%i IN (1,1,5) DO (
set /A COUNT+=1
:: %COUNT% だと正しく更新されない。!COUNT! を使う
echo %%i 回目 合計: !COUNT!
)
echo 最終カウント: %COUNT%
pause
| 参照方法 |
展開タイミング |
ループ内での使用 |
| %変数% |
ブロック解析時(実行前) |
❌ ループ内の更新を反映しない |
| !変数! |
実行時(遅延展開) |
✅ ループ内の更新を反映する |
実務パターン集
パターン1:フォルダ内の全ファイルをバックアップコピーする
backup.bat
@echo off
chcp 932 >nul
setlocal EnableDelayedExpansion
set SRC=C:workdata
set DST=C:ackup\%date:~0,4%%date:~5,2%%date:~8,2%
mkdir %DST% 2>nul
FOR %%f IN (%SRC%*.xlsx) DO (
copy "%%f" "%DST%" >nul
echo バックアップ完了: %%~nxf
)
echo 完了。保存先: %DST%
pause
パターン2:ファイル名一覧をCSVに出力する
list_to_csv.bat
@echo off
chcp 932 >nul
echo ファイル名,サイズ(byte),更新日時 > filelist.csv
FOR %%f IN (C:work*.*) DO (
echo %%~nxf,%%~zf,%%~tf >> filelist.csv
)
echo filelist.csv を出力しました
pause
パターン3:IPアドレス一覧に対してpingを一括実行する
ping_check.bat(ip_list.txt に 1行1IPを記載)
@echo off
chcp 932 >nul
FOR /F "delims=" %%i IN (ip_list.txt) DO (
ping -n 1 %%i >nul 2>&1
IF %ERRORLEVEL%==0 (
echo [OK] %%i
) ELSE (
echo [FAIL] %%i
)
)
pause
よくある失敗例と対処法
| 症状 |
原因 |
対処法 |
| ループが動かない / 変数が空になる |
%%i ではなく %i と書いている |
バッチファイル内では必ず %%i |
| FOR /F でファイル内の ; 始まり行がスキップされる |
デフォルトで ; 始まりの行がコメント扱いになる |
"eol=|" など使わない文字を eol に指定 |
| ループ内でSETした値が反映されない |
遅延展開が無効で %変数% を使っている |
setlocal EnableDelayedExpansion + !変数! に変更 |
| スペースを含むパスでエラーになる |
変数をダブルクォートで囲んでいない |
"%%f" のようにダブルクォートで囲む |
| FOR /F でテキストを読むと1列目しか取得できない |
delims= の指定がなくスペースで分割されている |
"delims="(空文字)を指定して行全体を取得 |
| 空フォルダで FOR /R を実行するとエラーになる |
マッチするファイルがゼロの場合も変数に値が入ることがある |
IF EXIST "%%f" で存在確認してから処理 |
まとめ
FOR文の5種類の構文を整理すると次の通りです。
| 構文 |
使い所 |
まず覚えるべき書き方 |
| FOR %%i IN (*) |
ファイルの一括処理 |
FOR %%f IN (*.txt) DO echo %%f |
| FOR /L %%i IN (1,1,10) |
数値カウンターループ |
FOR /L %%i IN (1,1,10) DO echo %%i |
| FOR /F %%L IN (file.txt) |
ファイル・コマンド出力解析 |
FOR /F “delims=” %%L IN (f.txt) DO echo %%L |
| FOR /D %%d IN (*) |
フォルダ名のループ |
FOR /D %%d IN (*) DO echo %%d |
| FOR /R %%f IN (*.log) |
再帰的なファイル処理 |
FOR /R %%f IN (*.log) DO echo %%f |
ポイント:まずは FOR /L(数値ループ)と FOR /F "delims=" %%L IN (ファイル)(ファイル読み込み)の2パターンを覚えるだけで、実務の大半のループ処理に対応できます。バッチファイル内では %%(二重)を忘れずに。
よくある質問
❓ FOR /F でテキストファイルを読むとき空行がスキップされるのはなぜですか? (クリックで開閉)
FOR /F は仕様として空行を自動的にスキップします。これは変更できません。空行も含めてすべての行を処理したい場合は、PowerShellの Get-Content や findstr /R "^" を組み合わせる方法があります。
❓ FOR文の中から GOTO でジャンプできますか? (クリックで開閉)
FORループの内部から GOTO でラベルへジャンプするとループが強制終了されます。これは仕様です。ループを途中で抜けたい場合は GOTO が有効な手段です。ただし、ループを継続しながら特定の反復だけスキップしたい場合は IF 文で条件分岐させてください。
❓ FOR文はネスト(入れ子)にできますか? (クリックで開閉)
できます。ネストする場合は変数名を別のアルファベットにする必要があります(例:外側が %%i、内側が %%j)。同じ変数名を使うと内側のループが外側の変数を上書きしてしまいます。
FOR /L %%i IN (1,1,3) DO (
FOR /L %%j IN (1,1,3) DO (
echo %%i x %%j = <SET /A %%i * %%j>
)
)