【bat】バッチファイルで指定フォルダ配下のフォルダ一覧を取得する方法完全ガイド|for /d・dir・再帰・フィルタ・CSV出力・実践パターンまで

バッチファイルでフォルダ一覧を取得したい場面は多くあります。バックアップ対象の確認・古いフォルダの検出・フォルダ構造の記録など、様々な自動化タスクの基盤になるテクニックです。

この記事では バッチファイルで指定フォルダ配下のフォルダ一覧を取得する全手法 を体系的に解説します。基本の1行コマンドから「再帰的な全サブフォルダ取得」「条件フィルタ」「CSV出力」まで網羅します。

この記事でわかること

  • for /d でサブフォルダ一覧を取得する方法(基本)
  • dir /ad /b コマンドとの使い分け
  • サブフォルダを再帰的にすべて取得する方法(for /r)
  • フォルダ名パターンでフィルタする方法
  • フォルダ一覧をCSV・テキストファイルに出力する方法
  • フォルダ数をカウントする方法
  • フォルダの作成日時・更新日時を取得する方法
  • 落とし穴5選・実践例3本・FAQ6問
スポンサーリンク
  1. 1. 基本:for /d でサブフォルダ一覧を取得
    1. 1-1. 最もシンプルな書き方
    2. 1-2. フォルダの存在チェック付き(エラーハンドリング)
  2. 2. dir /ad /b でフォルダ一覧を取得
    1. 2-1. dir コマンドの基本
    2. 2-2. dir 出力を for /f でループ処理
  3. 3. for /d と dir /ad /b の使い分け
  4. 4. サブフォルダを再帰的にすべて取得
    1. 4-1. dir /ad /b /s(最もシンプルな再帰)
    2. 4-2. for /r で再帰的にフォルダをループ
  5. 5. フォルダ名パターンでフィルタ
    1. 5-1. for /d のワイルドカードでフィルタ
    2. 5-2. findstr でフィルタ(より柔軟)
  6. 6. フォルダ一覧をCSV・テキストファイルに出力
    1. 6-1. テキストファイルに出力(シンプル)
    2. 6-2. CSV形式で出力(番号・フォルダ名・フルパス)
    3. 6-3. 日付付きファイル名で出力(タイムスタンプログ)
  7. 7. フォルダ数をカウント
    1. 7-1. find /c でカウント(シンプル)
    2. 7-2. for /d でカウント(変数に格納)
    3. 7-3. フォルダ数を条件で使う(閾値チェック)
  8. 8. フォルダの作成日時・更新日時を取得
    1. 8-1. forfiles でフォルダ情報を取得
    2. 8-2. dir /ad でタイムスタンプ付きリスト
  9. 9. 落とし穴5選と対策
    1. 落とし穴1:for /d は直下1階層のみ。サブフォルダの中には入らない
    2. 落とし穴2:フォルダ名にスペースが含まれると for /d が分割されて失敗する
    3. 落とし穴3:dir /b なしで使うと . と .. がリストに混入する
    4. 落とし穴4:for /f で dir の出力をパイプするとき ^ でエスケープが必要
    5. 落とし穴5:対象フォルダが存在しないと dir がエラーを返してスクリプトが止まる
  10. 10. 実践例3本
    1. 実践例1:バックアップ対象フォルダを自動検出してrobocopyで一括コピー
    2. 実践例2:古いフォルダを検出してCSVに記録
    3. 実践例3:2つのフォルダ構造を比較して差分を出力
  11. まとめ:使い分け早見表
  12. FAQ

1. 基本:for /d でサブフォルダ一覧を取得

for /d はフォルダ(ディレクトリ)専用のループ構文です。指定したパスの直下にあるフォルダのみを対象にします(サブフォルダの中までは入りません)。

1-1. 最もシンプルな書き方

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\work"

:: for /d: 指定パス直下のフォルダ(ディレクトリ)のみをループ
for /d %%D in ("%TARGET%\*") do (
    echo %%~nxD
)
endlocal
%%~nxD の意味
%%~nxD はフォルダ名のみ(パスなし)を取得します。%%D だとフルパスになります。変数修飾子の詳細は ファイルの拡張子一括変換ガイド のfor修飾子テーブルも参照してください。

1-2. フォルダの存在チェック付き(エラーハンドリング)

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\work"

:: 対象フォルダの存在確認
if not exist "%TARGET%\" (
    echo [ERROR] フォルダが見つかりません: %TARGET%
    exit /b 1
)

set "COUNT=0"
for /d %%D in ("%TARGET%\*") do (
    echo %%~nxD
    set /a COUNT+=1
)

if !COUNT! equ 0 (
    echo サブフォルダが見つかりませんでした
) else (
    echo.
    echo 合計: !COUNT! フォルダ
)
endlocal

2. dir /ad /b でフォルダ一覧を取得

dir コマンドに /ad(ディレクトリのみ)と /b(シンプル表示)を組み合わせると、フォルダ名だけのリストが得られます。

2-1. dir コマンドの基本

:: /a:d または /ad : ディレクトリ(フォルダ)のみ表示
:: /b        : ファイル名のみ(余分な情報なし)
dir /ad /b "C:\work"

:: 出力例:
:: backup
:: logs
:: temp
:: work2024

2-2. dir 出力を for /f でループ処理

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\work"

for /f "delims=" %%D in ('dir /ad /b "%TARGET%"') do (
    echo フォルダ名: %%D
)
endlocal
dir /ad /b の注意点
コマンドプロンプトで直接実行するとき、バッチファイルでは for /f ... in ('dir ...') の形で使います。フォルダが1件もない場合は dir がエラーを返すため、2>nul でエラーを抑制するか if exist で事前チェックしてください。

3. for /d と dir /ad /b の使い分け

項目 for /d dir /ad /b
構文のシンプルさ ループ内で直接処理できる for /f と組み合わせが必要
フルパス取得 %%D または %%~fD dir /ad /b /s でフルパス
再帰(全サブフォルダ) for /r か dir /s が必要 /s オプションで可能
ソート ファイルシステム順(固定) /o:n 等でソート指定可能
フィルタ(名前パターン) ワイルドカード使用可 ワイルドカード使用可
ファイルに出力 リダイレクトで出力 > でそのまま出力
おすすめ用途 ループ処理・変数操作 一覧表示・ファイル出力・再帰

4. サブフォルダを再帰的にすべて取得

直下のサブフォルダだけでなく、孫・ひ孫フォルダも含めてすべてリストアップするパターンです。

4-1. dir /ad /b /s(最もシンプルな再帰)

:: /s : サブフォルダも再帰的に検索
dir /ad /b /s "C:\work"

:: フルパスでリストアップ
dir /ad /b /s "C:\work" 2>nul

:: for /f でループ処理(フルパスで取得)
@echo off
for /f "delims=" %%D in ('dir /ad /b /s "C:\work" 2^>nul') do (
    echo %%D
)

4-2. for /r で再帰的にフォルダをループ

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\work"
set "COUNT=0"

:: for /r %%D in (.) : 各サブフォルダに .(カレント) を探索 → フォルダパスを取得
for /r "%TARGET%" %%D in (.) do (
    :: %%~dpD : ドライブ+パス部分(末尾に\が付く)
    :: 対象フォルダ自体は除外
    if /i not "%%~dpD" == "%TARGET%\" (
        echo %%~dpD
        set /a COUNT+=1
    )
)
echo 合計: !COUNT! フォルダ
endlocal
for /r で再帰フォルダを取得する仕組み
for /r "C:\work" %%D in (.) は、C:\work 以下のすべてのフォルダに対して .(カレントディレクトリ参照)を当てはめます。%%~dpD でフォルダのドライブ+パスが取得できます。dir /ad /b /s と組み合わせた for /f 方式の方が直感的なため、再帰処理では dir /s 方式を推奨します。

5. フォルダ名パターンでフィルタ

特定の文字列を含むフォルダだけを取得するパターンです。

5-1. for /d のワイルドカードでフィルタ

@echo off

:: "backup" で始まるフォルダのみ取得
for /d %%D in ("C:\work\backup*") do (
    echo %%~nxD
)

:: "2024" を含むフォルダ(ワイルドカードで前後を指定)
for /d %%D in ("C:\work\*2024*") do (
    echo %%~nxD
)

5-2. findstr でフィルタ(より柔軟)

@echo off
setlocal enabledelayedexpansion

:: dir + findstr で "log" を含むフォルダのみ表示
for /f "delims=" %%D in ('dir /ad /b "C:\work" ^| findstr /i "log"') do (
    echo %%D
)

:: 再帰的 + フィルタ("2024" を含むフォルダ)
for /f "delims=" %%D in ('dir /ad /b /s "C:\work" ^| findstr /i "2024"') do (
    echo %%D
)
endlocal

条件分岐・フィルタ処理の詳細は バッチファイルで条件分岐する方法完全ガイド を参照してください。

6. フォルダ一覧をCSV・テキストファイルに出力

フォルダ一覧を記録・共有するためにファイルに出力するパターンです。

6-1. テキストファイルに出力(シンプル)

:: カレントフォルダのサブフォルダ一覧をテキストファイルに保存
dir /ad /b "C:\work" > "C:\output\folder_list.txt"

:: 再帰的(全サブフォルダ)をテキストファイルに保存
dir /ad /b /s "C:\work" > "C:\output\folder_list_all.txt"

:: 追記モード(既存ファイルに追加)
dir /ad /b "C:\work" >> "C:\output\folder_list.txt"

6-2. CSV形式で出力(番号・フォルダ名・フルパス)

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\work"
set "OUT=C:\output\folder_list.csv"
set "NUM=0"

:: ヘッダー行
echo No,フォルダ名,フルパス > "%OUT%"

for /d %%D in ("%TARGET%\*") do (
    set /a NUM+=1
    echo !NUM!,%%~nxD,%%~fD >> "%OUT%"
)

echo [OK] CSV出力完了: %OUT% (!NUM! 件)
endlocal

6-3. 日付付きファイル名で出力(タイムスタンプログ)

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\work"

:: 今日の日付を取得(YYYYMMDD形式)
for /f "tokens=2 delims==." %%D in ('wmic os get LocalDateTime /value ^| findstr LocalDateTime') do set "DT=%%D"
set "TODAY=%DT:~0,8%"

set "OUT=C:\logs\folder_list_%TODAY%.txt"
dir /ad /b "%TARGET%" > "%OUT%"
echo 出力完了: %OUT%
endlocal

日付をファイル名に使う方法の詳細は 日付と時間をファイル名に挿入する方法完全ガイド を参照してください。

7. フォルダ数をカウント

サブフォルダの件数を取得するパターンです。処理前の確認や、変化を検知する監視スクリプトに使えます。

7-1. find /c でカウント(シンプル)

:: dir /ad /b の出力行数 = フォルダ数
dir /ad /b "C:\work" 2>nul | find /c /v ""

:: 再帰(全サブフォルダ数)
dir /ad /b /s "C:\work" 2>nul | find /c /v ""

7-2. for /d でカウント(変数に格納)

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\work"
set "COUNT=0"

for /d %%D in ("%TARGET%\*") do (
    set /a COUNT+=1
)

echo サブフォルダ数: !COUNT!
endlocal

7-3. フォルダ数を条件で使う(閾値チェック)

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\logs"
set "MAX=100"
set "COUNT=0"

for /d %%D in ("%TARGET%\*") do set /a COUNT+=1

if !COUNT! gtr %MAX% (
    echo [WARN] フォルダが %MAX% 件を超えています: !COUNT! 件
) else (
    echo [OK] フォルダ数: !COUNT! 件 / 上限 %MAX% 件
)
endlocal

8. フォルダの作成日時・更新日時を取得

フォルダのタイムスタンプを取得することで、古いフォルダの検出や更新履歴の記録が可能になります。

8-1. forfiles でフォルダ情報を取得

@echo off

:: @ISDIR==TRUE : フォルダのみ処理(ファイルはスキップ)
:: @FILE: 名前, @FDATE: 更新日付, @FTIME: 更新時刻
forfiles /p "C:\work" /c "cmd /c if @ISDIR==TRUE echo @FILE @FDATE @FTIME"

:: 30日以上更新されていないフォルダを検出
forfiles /p "C:\work" /d -30 /c "cmd /c if @ISDIR==TRUE echo 古いフォルダ: @FILE"

8-2. dir /ad でタイムスタンプ付きリスト

:: /ad: フォルダのみ, /tc: 作成日時でソート表示
dir /ad /tc "C:\work"

:: /o-d: 更新日時の新しい順でソート
dir /ad /o-d "C:\work"

:: 更新日時の古い順(最も古いフォルダが先頭)
dir /ad /od "C:\work"
forfiles の /d オプション
forfiles /d -30 は「30日以上前に更新されたファイル/フォルダ」を対象にします。/d +0 は今日以降に更新されたもの、/d 2024/01/01 のように日付指定も可能です。

9. 落とし穴5選と対策

落とし穴1:for /d は直下1階層のみ。サブフォルダの中には入らない

:: NG: for /d はネストしたフォルダを取得しない
:: C:\work\ 直下のフォルダしかリストアップされない
for /d %%D in ("C:\work\*") do echo %%D

:: OK: 再帰的に取得したい場合は dir /s か for /r を使う
for /f "delims=" %%D in ('dir /ad /b /s "C:\work" 2^>nul') do echo %%D

落とし穴2:フォルダ名にスペースが含まれると for /d が分割されて失敗する

:: NG: スペースを含むフォルダ名が分割される
for /d %%D in (C:\work\*) do echo %%D

:: OK: 必ずダブルクォートで囲む
for /d %%D in ("C:\work\*") do echo %%D

:: NG: 変数を展開するとき引用符を忘れる
set "TARGET=C:\my work"
for /d %%D in (%TARGET%\*) do echo %%D  :: スペースで分割される

:: OK: 変数展開も引用符で囲む
for /d %%D in ("%TARGET%\*") do echo %%D

落とし穴3:dir /b なしで使うと . と .. がリストに混入する

:: NG: /b なしの dir はヘッダー行・. と .. もリストアップされる
for /f "delims=" %%D in ('dir /ad "C:\work"') do echo %%D
:: → ヘッダー/フッター行・. (カレント)・.. (親) も処理対象に入ってしまう

:: OK: /b オプションを付けることで . と .. は表示されず純粋なフォルダ名のみになる
for /f "delims=" %%D in ('dir /ad /b "C:\work" 2^>nul') do echo %%D

落とし穴4:for /f で dir の出力をパイプするとき ^ でエスケープが必要

:: NG: パイプ | をエスケープしないと for /f がコマンドとして解釈する
for /f "delims=" %%D in ('dir /ad /b "C:\work" | findstr "log"') do echo %%D

:: OK: バッチファイル内では ^ でエスケープ
for /f "delims=" %%D in ('dir /ad /b "C:\work" ^| findstr "log"') do echo %%D

:: OK: > も同様にエスケープが必要
for /f "delims=" %%D in ('dir /ad /b /s "C:\work" 2^>nul') do echo %%D

落とし穴5:対象フォルダが存在しないと dir がエラーを返してスクリプトが止まる

:: NG: フォルダが存在しない場合にエラーが表示される
for /d %%D in ("C:\nonexistent\*") do echo %%D

:: OK: 事前に存在チェックを行う
set "TARGET=C:\work"
if not exist "%TARGET%\" (
    echo [ERROR] フォルダが存在しません: %TARGET%
    exit /b 1
)
for /d %%D in ("%TARGET%\*") do echo %%~nxD

:: OK: 2>nul でエラーを抑制する方法(エラーチェックなし)
dir /ad /b "C:\work" 2>nul

エラーハンドリングの詳細は ERRORLEVELを使ったエラーハンドリング完全ガイド を参照してください。

10. 実践例3本

実践例1:バックアップ対象フォルダを自動検出してrobocopyで一括コピー

指定フォルダ直下のサブフォルダを全てバックアップするパターンです。新しく作られたフォルダも自動的にバックアップ対象になります。

@echo off
setlocal enabledelayedexpansion

set "SRC_ROOT=C:\projects"
set "DST_ROOT=D:\backup\projects"
set "LOG=C:\logs\backup_log.txt"
set "COUNT=0"

if not exist "%DST_ROOT%" mkdir "%DST_ROOT%"

:: src_root 直下のサブフォルダを1つずつバックアップ
for /d %%D in ("%SRC_ROOT%\*") do (
    echo [START] %%~nxD のバックアップ中...
    robocopy "%%D" "%DST_ROOT%\%%~nxD" /MIR /R:2 /W:5 /LOG+:"%LOG%" /NP /NDL
    if !ERRORLEVEL! leq 3 (
        echo [OK] %%~nxD 完了
        set /a COUNT+=1
    ) else (
        echo [ERROR] %%~nxD でエラー発生 (ERRORLEVEL=!ERRORLEVEL!)
    )
)

echo ===== バックアップ完了: !COUNT! フォルダ =====
endlocal
robocopy の ERRORLEVEL 3 以下はOK
robocopy は正常終了でも 0・1・2・3 を返します(コピーしたファイルの数によって変わる)。4 以上がエラーのため if !ERRORLEVEL! leq 3 で判定します。

フォルダコピーの詳細は バッチファイルでフォルダをコピーする方法完全ガイド を参照してください。

実践例2:古いフォルダを検出してCSVに記録

指定日数以上更新のないフォルダを検出してCSVに記録するパターンです。定期メンテナンスや容量管理に役立ちます。

@echo off
setlocal enabledelayedexpansion

set "TARGET=C:\archive"
set "DAYS=90"
set "OUT=C:\reports\old_folders.csv"

:: 今日の日付を取得
for /f "tokens=2 delims==." %%D in ('wmic os get LocalDateTime /value ^| findstr LocalDateTime') do set "DT=%%D"
set "TODAY=%DT:~0,8%"

echo 日付,フォルダ名,フルパス > "%OUT%"

set "FOUND=0"
forfiles /p "%TARGET%" /d -%DAYS% /c "cmd /c if @ISDIR==TRUE echo %TODAY%,@FILE,@PATH" >> "%OUT%" 2>nul

:: 件数をカウント
for /f %%N in ('find /c /v "" "%OUT%"') do set "LINES=%%N"
set /a FOUND=!LINES! - 1

echo [OK] %DAYS%日以上未更新フォルダ: !FOUND! 件 -> %OUT%
endlocal

実践例3:2つのフォルダ構造を比較して差分を出力

本番フォルダとバックアップフォルダのサブフォルダ構成を比較し、片方にしかないフォルダを検出するパターンです。

@echo off
setlocal enabledelayedexpansion

set "FOLDER_A=C:\production"
set "FOLDER_B=D:\backup\production"
set "TMPFILE=%TEMP%\folders_a_%RANDOM%.tmp"
set "DIFF_COUNT=0"

:: Aのフォルダ一覧を一時ファイルに保存
dir /ad /b "%FOLDER_A%" 2>nul > "%TMPFILE%"

:: Aにあって B にないフォルダを検出
echo ===== A にあって B にないフォルダ =====
:: usebackq: ファイル名にスペースが含まれても正しく読み込む
for /f "usebackq delims=" %%D in ("%TMPFILE%") do (
    if not exist "%FOLDER_B%\%%D" (
        echo [ONLY_A] %%D
        set /a DIFF_COUNT+=1
    )
)

:: B にあって A にないフォルダを検出
echo ===== B にあって A にないフォルダ =====
for /d %%D in ("%FOLDER_B%\*") do (
    if not exist "%FOLDER_A%\%%~nxD" (
        echo [ONLY_B] %%~nxD
        set /a DIFF_COUNT+=1
    )
)

del "%TMPFILE%" 2>nul

if !DIFF_COUNT! equ 0 (
    echo [OK] フォルダ構造は一致しています
) else (
    echo [WARN] 差分: !DIFF_COUNT! フォルダ
)
endlocal

フォルダの一括ループ処理の詳細は 複数フォルダをループして一括処理する方法完全ガイド を参照してください。

まとめ:使い分け早見表

やりたいこと コマンド ポイント
直下のサブフォルダをループ for /d %%D in ("パス\*") do ループ処理・変数操作向き
サブフォルダ名だけ一覧表示 dir /ad /b "パス" シンプル・ファイル出力向き
再帰的に全サブフォルダ取得 dir /ad /b /s "パス" 全階層を一括取得
for /f で再帰ループ for /f ... in ('dir /ad /b /s ...') 各フォルダでバッチ処理
名前パターンでフィルタ for /d %%D in ("パス\*keyword*") ワイルドカード使用可
CSV出力 for /d + echo No,名前,パス >> CSV setlocal enabledelayedexpansion 必須
フォルダ数カウント dir /ad /b 2>nul | find /c /v "" 1行で取得可能
古いフォルダ検出 forfiles /d -日数 /c "if @ISDIR==TRUE ..." 日数・日付で柔軟フィルタ

setlocal enabledelayedexpansion 完全ガイド も合わせて参照してください。

FAQ

Q. for /d でサブフォルダを取得すると1件も取れません。
A. 主な原因は2つです。①パターンに * を忘れている("C:\work\" ではなく "C:\work\*")、②対象フォルダ直下にサブフォルダが存在しない。dir /ad "C:\work" でサブフォルダの有無を確認してください。
Q. フォルダ名にスペースが含まれているとリストが崩れます。
A. for /d %%D in ("%TARGET%\*") do のように、パターンをダブルクォートで囲んでください。また %%D を使う箇所でも "%%D" と引用符をつけると安全です。
Q. サブフォルダの中のサブフォルダ(2階層以上)も全部取得したい。
A. dir /ad /b /s "C:\work" または for /f "delims=" %%D in ('dir /ad /b /s "C:\work" 2^>nul') を使います。for /d は直下1階層のみです。
Q. フォルダ一覧をテキストファイルに保存するには?
A. dir /ad /b "C:\work" > "output.txt" でシンプルに出力できます。追記は >>、ファイル名に日付を付けるには %DATE:~0,4%%DATE:~5,2%%DATE:~8,2% または wmic で取得した日付文字列を使います。
Q. for /f でdir の出力をパイプするとエラーになります。
A. バッチファイル内でパイプ | や リダイレクト >for /f のコマンド部分で使うときは ^ でエスケープが必要です。例: 'dir /ad /b "C:\work" ^| findstr "log"'
Q. 隠しフォルダも含めて一覧取得したい。
A. dir /a:dh /b "C:\work"(隠しフォルダのみ)または dir /a:d /b "C:\work" では通常フォルダのみです。隠し属性も含む全フォルダは attrib /d /s "C:\work\*" | findstr "D" や PowerShell の Get-ChildItem -Force -Directory の方が確実です。