「複数のフォルダに対して同じ処理を繰り返したい」「サブフォルダ内のファイルをまとめて移動したい」——バッチファイルでフォルダをループ処理する場面は多くあります。本記事では for /d・for /r・指定リストの3つのループ構文を軸に、ネストループ・実践パターン・よくある落とし穴まで体系的に解説します。
- カレントディレクトリのサブフォルダ全体を
for /dでループする方法 for /rで全階層のフォルダ・ファイルを再帰的に処理する方法- コード内リスト・テキストファイルからフォルダを読み込んでループする方法
- フォルダ→ファイルのネストループで一括処理する実践スクリプト
- パスにスペースがある場合の対処・遅延展開が必要な場面
ループ方法の比較
| 構文 | 対象 | 特徴 |
|---|---|---|
for /d %%F in (*) do |
カレントの直下サブフォルダ | シンプル・最もよく使う |
for /d %%F in (C:ase*) do |
指定パスの直下サブフォルダ | カレント以外のパスを対象にできる |
for /r %%F in (.) do |
全階層のサブフォルダ(再帰) | 深いフォルダ構造を一括処理 |
for %%F in (A B C) do |
コード内に列挙したフォルダ | 対象フォルダが固定の場合に便利 |
for /f %%F in (list.txt) do |
テキストファイルのフォルダリスト | 対象が多い場合・動的変更しやすい |
%%F に修飾子を付けると、フルパス・フォルダ名・ドライブ名などを個別に取得できます。%%~fF=フルパス、%%~nF=名前のみ(拡張子なし)、%%~dpF=ドライブ+ディレクトリ部分。パスにスペースが含まれる場合は
"%%~fF" のようにダブルクォートで囲むのが基本です。
方法1: for /d でカレントのサブフォルダをループ
最も基本的なパターンです。カレントディレクトリ直下にあるすべてのフォルダに対してループします。
基本構文
@echo off
setlocal
rem カレントディレクトリの直下サブフォルダをループ
for /d %%F in (*) do (
echo フォルダ名: %%F
echo フルパス : %%~fF
)
endlocal
特定パスの直下サブフォルダを対象にする
@echo off
setlocal
set BASE=C:workprojects
rem 指定パス直下のサブフォルダをループ
for /d %%F in ("%BASE%*") do (
echo フォルダ名: %%~nxF
echo フルパス : %%~fF
)
endlocal
for /d は直下のサブフォルダのみ対象for /d %%F in (*) do はカレントの 直下1階層 のフォルダだけを対象にします。さらに深い階層(孫フォルダ以降)も処理したい場合は
for /r を使ってください。
方法2: for /r で全階層を再帰探索
ルートフォルダ以下のすべての階層を再帰的にたどります。深いフォルダ構造を一括処理する場合に使います。
全サブフォルダを再帰的にループ
@echo off
setlocal enabledelayedexpansion
set ROOT=C:workdata
rem ROOT 配下の全フォルダ(全階層)をループ
for /r "%ROOT%" %%F in (.) do (
rem %%F は "フォルダ内の ." = そのフォルダ自体を指す
rem %%~dpF でディレクトリパスを取得
set DIRPATH=%%~dpF
rem 末尾の を除去してフォルダ名を取得
set DIRPATH=!DIRPATH:~0,-1!
echo サブフォルダ: !DIRPATH!
)
endlocal
for /r %%F in (.) の注意点%%F の値は C:workdatasub. のように末尾に . が付きます。フォルダパスとして使うには
%%~dpF(末尾 付き)か、setlocal enabledelayedexpansion で末尾を除去して使います。詳しくは setlocal enabledelayedexpansion 完全ガイド を参照してください。
全階層の特定拡張子ファイルを再帰検索
@echo off
setlocal
set ROOT=C:workdata
rem ROOT 配下のすべての .log ファイルを再帰的に列挙
for /r "%ROOT%" %%F in (*.log) do (
echo ログファイル: %%~fF
echo サイズ: %%~zF バイト
)
endlocal
方法3: 指定したフォルダのリストをループ
処理対象フォルダが固定で決まっている場合は、コード内にリストを書く方法が読みやすくて保守しやすいです。
コード内にフォルダリストを記述
@echo off
setlocal
rem 処理したいフォルダをスペース区切りで列挙
for %%F in (
"C:workproject_A"
"C:workproject_B"
"C:workproject_C"
) do (
if exist %%F (
echo 処理中: %%~F
) else (
echo スキップ(存在しない): %%~F
)
)
endlocal
テキストファイルからフォルダリストを読み込む
対象フォルダが多い場合や動的に変更したい場合は、外部テキストファイルで管理します。
@echo off
setlocal
rem folder_list.txt の内容(1行1フォルダ)
rem C:workproject_A
rem C:workproject_B
rem C:workproject_C
set LISTFILE=%~dp0folder_list.txt
if not exist "%LISTFILE%" (
echo エラー: %LISTFILE% が見つかりません
exit /b 1
)
for /f "usebackq delims=" %%F in ("%LISTFILE%") do (
if exist "%%F" (
echo 処理中: %%F
) else (
echo スキップ(存在しない): %%F
)
)
endlocal
for /f "usebackq" を指定すると、バッククォート `command` でコマンド実行、ダブルクォート "filename" でファイル読み込みができます。ファイルパスにスペースが含まれる場合に
"usebackq" が必要になります。
ネストループ: フォルダ→ファイルを一括処理
「各サブフォルダの中にあるファイルを処理する」という最も多いパターンです。
各サブフォルダの全ファイルを処理
@echo off
setlocal
rem カレントの各サブフォルダに入り、全ファイルを列挙
for /d %%F in (*) do (
echo === フォルダ: %%F ===
for %%G in ("%%F*") do (
echo ファイル: %%~nxG サイズ: %%~zG バイト
)
)
endlocal
各サブフォルダの特定拡張子ファイルのみ処理
@echo off
setlocal
for /d %%F in (*) do (
echo === フォルダ: %%~nxF ===
for %%G in ("%%F*.csv") do (
echo CSV: %%~nxG
)
)
endlocal
実践例A: 各フォルダの.txtファイルを1か所に収集する
@echo off
setlocal
set DEST=%~dp0collected_txt
if not exist "%DEST%" mkdir "%DEST%"
set COUNT=0
for /d %%F in (*) do (
for %%G in ("%%F*.txt") do (
echo コピー: %%~fG → %DEST%
copy "%%~fG" "%DEST%" >nul
set /a COUNT+=1
)
)
echo.
echo 完了: %COUNT% ファイルをコピーしました
endlocal
実践例B: 各フォルダにログファイルを自動生成する
@echo off
setlocal
rem 現在時刻を取得
set NOW=%DATE% %TIME%
for /d %%F in (*) do (
rem 各フォルダに processed.log を作成・追記
(
echo ===========================
echo 処理日時: %NOW%
echo フォルダ: %%~fF
echo ファイル数:
dir /b /a-d "%%F*" 2>nul | find /c /v ""
echo ===========================
) >> "%%Fprocessed.log"
echo ログ作成: %%Fprocessed.log
)
endlocal
実践例C: 特定パターンのフォルダだけ処理する
フォルダ名に「backup_」が含まれるフォルダだけ処理する例です。
@echo off
setlocal enabledelayedexpansion
for /d %%F in (*) do (
set FNAME=%%~nxF
rem フォルダ名に "backup_" が含まれるか確認
echo !FNAME! | findstr /i "backup_" >nul
if not errorlevel 1 (
echo 対象フォルダ: %%F
rem ここに処理を記述
) else (
echo スキップ: %%F
)
)
endlocal
ワイルドカードで絞り込む方法(シンプル)
@echo off
setlocal
rem "backup_" で始まるフォルダだけに for /d のパターンを適用
for /d %%F in (backup_*) do (
echo バックアップ対象: %%F
rem 処理をここに記述
)
endlocal
for /d %%F in (backup_*) do のようにパターンに直接ワイルドカードを使えば、if・findstr なしで目的のフォルダだけをループできます。前後一致・部分一致などが必要なケースは
findstr や if 条件との組み合わせを使いましょう。
実践例D: フォルダごとのファイル数・合計サイズをCSVに出力
@echo off
setlocal enabledelayedexpansion
set CSVFILE=%~dp0folder_summary.csv
rem ヘッダー
echo フォルダ名,ファイル数,合計サイズ(bytes) > "%CSVFILE%"
for /d %%F in (*) do (
set FCOUNT=0
set FSIZE=0
for %%G in ("%%F*") do (
set /a FCOUNT+=1
set /a FSIZE+=%%~zG
)
echo %%~nxF,!FCOUNT!,!FSIZE! >> "%CSVFILE%"
echo %%~nxF: !FCOUNT! files !FSIZE! bytes
)
echo.
echo CSV 出力完了: %CSVFILE%
endlocal
実践例E: ROBOCOPYで各フォルダをバックアップ
@echo off
setlocal enabledelayedexpansion
set BACKUP_ROOT=D:ackup\%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%
for /d %%F in ("C:work*") do (
set SRC=%%~fF
set DST=%BACKUP_ROOT%\%%~nxF
echo バックアップ中: !SRC! → !DST!
robocopy "!SRC!" "!DST!" /mir /r:2 /w:5 /log+:"%BACKUP_ROOT%
obocopy_%%~nxF.log" >nul
if errorlevel 8 (
echo [ERROR] %%~nxF のバックアップでエラーが発生しました
) else (
echo [OK] %%~nxF 完了
)
)
endlocal
ROBOCOPY の詳しい使い方は ROBOCOPYの使い方完全ガイド(ミラーリング・差分コピー・ログ出力) を参照してください。
よくある落とし穴
落とし穴1: パスにスペースがあるとフォルダが分断される
rem NG: パスにスペースがあると for /d が正しく動作しない
for /d %%F in (C:workmy projects*) do (
echo %%F
)
rem → "C:workmy" と "projects*" に分断される
rem OK: ダブルクォートで囲む
for /d %%F in ("C:workmy projects*") do (
echo %%~fF
)
落とし穴2: ネストしたFOR内で変数が更新されない
rem NG: enabledelayedexpansion なしでは COUNT が更新されない
@echo off
setlocal
set COUNT=0
for /d %%F in (*) do (
for %%G in ("%%F*.txt") do (
set /a COUNT+=1
)
)
echo %COUNT% ← 常に 0 になる!
rem OK: enabledelayedexpansion を使い !COUNT! で参照
@echo off
setlocal enabledelayedexpansion
set COUNT=0
for /d %%F in (*) do (
for %%G in ("%%F*.txt") do (
set /a COUNT+=1
)
)
echo !COUNT!
落とし穴3: for /r の結果に “.” が含まれる
rem for /r %%F in (.) は各フォルダの "." を対象にする
rem %%F の値例: C:worksub1. C:worksub2.
for /r "C:work" %%F in (.) do (
rem %%~dpF = "C:worksub1" (末尾 付きのディレクトリ)
echo %%~dpF
)
rem フォルダ名のみ(末尾 なし)が必要な場合は以下
setlocal enabledelayedexpansion
for /r "C:work" %%F in (.) do (
set D=%%~dpF
set D=!D:~0,-1! ← 末尾の を除去
echo !D!
)
落とし穴4: for /d は空フォルダもマッチする
rem for /d はファイルが入っていない空フォルダもループ対象になる
rem ファイルがあるフォルダだけ処理したい場合は dir で確認
for /d %%F in (*) do (
rem フォルダが空かどうかチェック
dir /b /a-d "%%F*" >nul 2>&1
if not errorlevel 1 (
echo ファイルあり: %%F
) else (
echo 空フォルダ(スキップ): %%F
)
)
落とし穴5: FORループ内でGOTOを使うとループが中断される
rem NG: for ループ内で goto するとループが終了してしまう
for /d %%F in (*) do (
if exist "%%Fimportant.txt" goto :found
)
rem OK: 条件分岐はループ内に収める・またはCALLでサブルーチン化
for /d %%F in (*) do (
call :process "%%F"
)
goto :end
:process
set FOLDER=%~1
if exist "%FOLDER%important.txt" (
echo 重要ファイルあり: %FOLDER%
)
goto :eof
:end
FOR ループ内での GOTO の制約については バッチファイルのラベル・GOTO・CALL 完全ガイド で詳しく解説しています。
よくある質問(FAQ)
if で除外条件を追加します。複数フォルダを除外する場合は if %%~nxF neq を連ねるか findstr で否定します。
@echo off
setlocal
rem "temp" と "logs" フォルダを除外してループ
for /d %%F in (*) do (
if /i "%%~nxF" neq "temp" (
if /i "%%~nxF" neq "logs" (
echo 処理中: %%F
)
)
)
endlocal
call :ラベル名 "%%F" でサブルーチンに引数としてフォルダパスを渡せます。処理が長い場合やネストが深くなる場合に有効です。
@echo off
setlocal
for /d %%F in (*) do (
call :process_folder "%%~fF"
)
goto :end
:process_folder
setlocal
set FOLDER=%~1
echo === 処理中: %FOLDER% ===
for %%G in ("%FOLDER%*.txt") do (
echo テキスト: %%~nxG
)
endlocal
goto :eof
:end
echo すべてのフォルダの処理が完了しました
CALL を使ったサブルーチン化の詳細は バッチファイルのサブルーチン完全ガイド を参照してください。
先に数を数えてから処理するには2パスで行います。
@echo off
setlocal enabledelayedexpansion
rem まずフォルダ数をカウント
set TOTAL=0
for /d %%F in (*) do set /a TOTAL+=1
echo 対象フォルダ数: %TOTAL%
rem 処理パス
set CURRENT=0
for /d %%F in (*) do (
set /a CURRENT+=1
echo [!CURRENT!/%TOTAL%] 処理中: %%F
rem 処理をここに記述
)
endlocal
for /d はファイルシステムの順序(通常はアルファベット順)でループします。日付順など特定の順序が必要な場合は、dir /o:d /b /ad の出力を for /f で受け取る方法が確実です。
@echo off
setlocal
rem 日付順(古い順)にサブフォルダをループ
for /f "delims=" %%F in ('dir /b /ad /o:d') do (
echo %%F
)
rem 名前の逆順(Z→A)
for /f "delims=" %%F in ('dir /b /ad /o:-n') do (
echo %%F
)
endlocal
深さを制限するにはサブルーチンで「深さカウンタ」を管理します。
@echo off
setlocal
set MAX_DEPTH=2
call :scan "C:work" 0
goto :end
:scan
setlocal
set DIR=%~1
set DEPTH=%~2
if %DEPTH% GEQ %MAX_DEPTH% goto :eof
echo %DIR%
set /a NEXT_DEPTH=%DEPTH%+1
for /d %%F in ("%DIR%*") do (
call :scan "%%~fF" %NEXT_DEPTH%
)
endlocal
goto :eof
:end
まとめ
| 目的 | 推奨構文 |
|---|---|
| カレントの直下サブフォルダを処理 | for /d %%F in (*) do |
| 指定パスの直下サブフォルダを処理 | for /d %%F in ("C:path*") do |
| 全階層のサブフォルダを再帰処理 | for /r "C:path" %%F in (.) do |
| 全階層の特定ファイルを再帰処理 | for /r "C:path" %%F in (*.ext) do |
| 固定フォルダリストをループ | for %%F in ("A" "B" "C") do |
| テキストファイルのフォルダ一覧をループ | for /f "usebackq delims=" %%F in ("list.txt") do |
| フォルダ→ファイルのネストループ | for /d %%F in (*) do ( for %%G in ("%%F*") do ) |
| 特定パターンのフォルダだけ処理 | for /d %%F in (prefix_*) do(ワイルドカード絞り込み) |
| ループ内で変数更新が必要 | setlocal enabledelayedexpansion + !VAR! で参照 |
FOR 文の構文全般については FOR文の使い方完全ガイド(ファイル・数値・文字列ループを網羅) を、フォルダ一覧の取得については バッチファイルで指定フォルダ配下のフォルダ一覧を取得する方法 も合わせて参照してください。

