【bat】ワイルドカードを使ってファイルを移動する方法完全ガイド|*・?・for /r・robocopy・ドライラン・実践パターンまで

【bat】ワイルドカードを使ってファイルを移動する方法完全ガイド|*・?・for /r・robocopy・ドライラン・実践パターンまで bat

バッチファイル(bat)でファイルを一括移動するとき、ワイルドカード(*?)を使えば、拡張子・ファイル名のパターンで一度に大量のファイルを移動できます。本記事では基本の move コマンドから、サブフォルダ再帰・robocopy /MOV・ドライランまで、実務で使える移動パターンを体系的に解説します。

この記事でできること

  • *? ワイルドカードでパターンに合うファイルを一括移動
  • 拡張子指定・プレフィックス・日付パターンなど多様な条件で絞り込む
  • サブフォルダを再帰的にたどって移動する(for /r + move)
  • robocopy /MOV でコピー後に元ファイルを削除する安全な移動
  • ドライランで実行前に対象ファイルを確認する
  • 実践例3本(バックアップ整理・ログ月別移動・一時ファイル削除)と落とし穴・FAQ も解説
スポンサーリンク
  1. ワイルドカードの基本
  2. 方法1: 拡張子・プレフィックスで一括移動
    1. 特定の拡張子のファイルをすべて移動
    2. ファイル名がプレフィックスで始まるファイルを移動
    3. 複数の拡張子を対象にする(ループ)
  3. 方法2: ? で文字数固定パターンの移動
    1. 4文字の連番ファイルを移動
    2. 日付パターン(YYYYMMDD)のファイルを移動
  4. 方法3: ドライランで移動前に対象ファイルを確認
  5. 方法4: サブフォルダを再帰的にたどって移動(for /r)
    1. サブフォルダ内の .tmp ファイルをすべて移動
    2. サブフォルダ構造を維持しながら移動(相対パス保持)
  6. 方法5: robocopy /MOV で安全な移動
    1. 基本: *.log を移動(/MOV)
    2. サブフォルダも含めて再帰移動(/MOV /S)
    3. ドライラン確認(/L オプション)
  7. 実践例A: 古いバックアップZIPを日付パターンで整理
  8. 実践例B: 30日以上前のログファイルを月別フォルダへ移動
  9. 実践例C: ビルド成果物を種別フォルダに振り分けて移動
  10. よくある落とし穴
    1. 落とし穴1: 移動先に同名ファイルがあると確認なしに上書き
    2. 落とし穴2: move はサブフォルダを再帰的に処理しない
    3. 落とし穴3: パスにスペースが含まれるとエラー
    4. 落とし穴4: 移動先フォルダが存在しないとエラー
    5. 落とし穴5: ? は1文字にのみマッチ・パスセパレータをまたがない
  11. よくある質問(FAQ)
  12. まとめ

ワイルドカードの基本

bat で使えるワイルドカードは *(任意の文字列)と ?(任意の1文字)の2種類です。

記号 意味 マッチ例 非マッチ例
* 0文字以上の任意の文字列 *.txt → a.txt, report_2024.txt *.txt → a.csv
? 任意の1文字(必ず1文字) file?.txt → file1.txt, fileA.txt file?.txt → file12.txt
*.* 拡張子を持つ全ファイル data.csv, log.txt (拡張子なしファイル)
????.* 4文字のファイル名(任意の拡張子) data.csv, logs.txt ab.txt, report.txt
move は上書きを確認しない
move コマンドは移動先に同名ファイルがあると確認なしに上書きします。重要ファイルを扱う場合は必ずドライランで確認するか、robocopy /MOV/XO(古いファイルのみ移動)や /L(一覧表示のみ)オプションを活用してください。

方法1: 拡張子・プレフィックスで一括移動

move コマンドに直接ワイルドカードを指定する最もシンプルな方法です。

特定の拡張子のファイルをすべて移動

@echo off
setlocal

set "SRC=C:\work\source"
set "DST=C:\work\dest"

if not exist "%DST%" mkdir "%DST%"

rem .txt ファイルをすべて移動
move "%SRC%\*.txt" "%DST%\"

echo 完了
endlocal

ファイル名がプレフィックスで始まるファイルを移動

@echo off
setlocal

set "SRC=C:\logs"
set "DST=C:\archive\logs"

if not exist "%DST%" mkdir "%DST%"

rem "error_" で始まるすべての .log ファイルを移動
move "%SRC%\error_*.log" "%DST%\"

echo エラーログを移動しました
endlocal

複数の拡張子を対象にする(ループ)

@echo off
setlocal

set "SRC=C:\work"
set "DST=C:\archive"

if not exist "%DST%" mkdir "%DST%"

rem .bak .tmp .log をそれぞれ移動
for %%E in (bak tmp log) do (
    move "%SRC%\*.%%E" "%DST%\" >nul 2>&1
)

echo 完了
endlocal

移動後にファイルの拡張子も変えたい場合は bat でファイルの拡張子を一括変換する方法 も合わせて参照してください。

方法2: ? で文字数固定パターンの移動

? は必ず1文字にマッチします。連番・日付・バージョン番号など文字数が決まっているパターンに有効です。

4文字の連番ファイルを移動

@echo off
setlocal

set "SRC=C:\data"
set "DST=C:\done"

if not exist "%DST%" mkdir "%DST%"

rem report_0001.csv ~ report_9999.csv にマッチ
move "%SRC%\report_????.csv" "%DST%\"

echo 完了
endlocal

日付パターン(YYYYMMDD)のファイルを移動

@echo off
setlocal

set "SRC=C:\backup"
set "DST=C:\old_backup"

if not exist "%DST%" mkdir "%DST%"

rem backup_20231231.zip のような 8桁日付パターン
move "%SRC%\backup_????????.zip" "%DST%\"

echo バックアップファイルをアーカイブに移動しました
endlocal

方法3: ドライランで移動前に対象ファイルを確認

実際に移動する前に、どのファイルが対象になるかを確認します。-dry オプションで確認のみ実行し、問題なければそのまま移動できます。

@echo off
setlocal enabledelayedexpansion

set "SRC=C:\work\logs"
set "DST=C:\archive\logs"
set "PATTERN=*.log"
set "DRY=0"

if "%1"=="-dry" set "DRY=1"

set /a COUNT=0

for %%F in ("%SRC%\%PATTERN%") do (
    set /a COUNT+=1
    if !DRY!==1 (
        echo [DRY] %%~nxF → %DST%
    ) else (
        if not exist "%DST%" mkdir "%DST%"
        move "%%F" "%DST%\"
    )
)

if !DRY!==1 (
    echo [DRY] 対象ファイル数: !COUNT! 件(実際には移動しません)
) else (
    echo 移動完了: !COUNT! 件
)
endlocal

方法4: サブフォルダを再帰的にたどって移動(for /r)

move コマンドはサブフォルダを自動でたどりません。for /r でサブフォルダを再帰的に検索し、マッチするファイルを移動します。

サブフォルダ内の .tmp ファイルをすべて移動

@echo off
setlocal enabledelayedexpansion

set "ROOT=C:\project"
set "DST=C:\cleanup\tmp_files"

if not exist "%DST%" mkdir "%DST%"

set /a COUNT=0

for /r "%ROOT%" %%F in (*.tmp) do (
    set /a COUNT+=1
    move "%%F" "%DST%\"
)

echo 再帰移動完了: !COUNT! 件
endlocal

サブフォルダ構造を維持しながら移動(相対パス保持)

移動先でも元のサブフォルダ構造を保ちたい場合は、%%~dpF(フォルダパス)を利用してサブフォルダを再現します。

@echo off
setlocal enabledelayedexpansion

set "ROOT=C:\src"
set "DST_ROOT=C:\dst"

for /r "%ROOT%" %%F in (*.log) do (
    rem 元フォルダの相対部分を取り出す
    set "SRCDIR=%%~dpF"
    set "REL=!SRCDIR:%ROOT%=!"
    set "DESTDIR=%DST_ROOT%!REL!"

    if not exist "!DESTDIR!" mkdir "!DESTDIR!"
    move "%%F" "!DESTDIR!"
)

echo フォルダ構造を維持して移動完了
endlocal

方法5: robocopy /MOV で安全な移動

robocopy はコピー後に元ファイルを削除する方式のため、move より安全です。ネットワーク越しの移動・再試行・ログ記録など運用向け機能も豊富です。

基本: *.log を移動(/MOV)

@echo off
setlocal

set "SRC=C:\logs\raw"
set "DST=C:\logs\archive"

rem /MOV: ファイルを移動(コピー後に削除)
rem /NFL /NDL: ファイル名リスト表示なし
rem /NJH /NJS: ヘッダー・サマリー非表示
robocopy "%SRC%" "%DST%" *.log /MOV /NFL /NDL /NJH /NJS

echo robocopy 移動完了
endlocal

サブフォルダも含めて再帰移動(/MOV /S)

@echo off
setlocal

set "SRC=C:\project\output"
set "DST=C:\archive\output"

rem /MOV /S: サブフォルダを含めて移動
rem /XO: 移動先の方が新しければスキップ(上書き防止)
robocopy "%SRC%" "%DST%" *.zip /MOV /S /XO

echo アーカイブへの移動完了
endlocal

ドライラン確認(/L オプション)

@echo off

rem /L: 実際には移動せず、対象ファイルの一覧だけ表示
robocopy "C:\src" "C:\dst" *.tmp /MOV /L

echo 上記が移動対象です(実際には移動していません)
move vs robocopy の選び方
move: シンプルで高速。同一ドライブ内なら実質リネーム(ファイルのコピーが発生しない)。
robocopy /MOV: ドライブ跨ぎ・ネットワーク越し・再試行・ログ記録が必要な場合に使う。

実践例A: 古いバックアップZIPを日付パターンで整理

想定: backup_YYYYMMDD.zip の形式でバックアップが溜まっている。指定した年月(YYYY-MM)のファイルを別フォルダへ移動します。

@echo off
setlocal enabledelayedexpansion

set "SRC=C:\backup\daily"
set "DST_BASE=C:\backup\monthly"

rem 移動対象の年月を指定(YYYYMM)
set "TARGET_YM=202401"

set "DST=%DST_BASE%\%TARGET_YM%"
if not exist "%DST%" mkdir "%DST%"

set /a MOVED=0

for %%F in ("%SRC%\backup_%TARGET_YM%??.zip") do (
    move "%%F" "%DST%\"
    set /a MOVED+=1
)

echo ========================
echo %TARGET_YM% のバックアップ整理完了
echo 移動件数: %MOVED% 件
echo 移動先  : %DST%
echo ========================
endlocal

特定の文字列を含むファイルだけを選んでコピー・移動する方法は bat で特定の文字列を含むファイルをコピーする方法 も合わせてご覧ください。

実践例B: 30日以上前のログファイルを月別フォルダへ移動

forfiles コマンドで更新日が古いファイルだけを対象にし、月別サブフォルダへ振り分けます。

PowerShell を組み合わせる理由
bat の %DATE% は OS のロケール設定によって形式が異なるため、月の抽出に使うと環境依存の問題が起きやすいです。PowerShell の Get-Item.LastWriteTime はロケール非依存で信頼性が高いため、ここでは PowerShell を利用しています。また、ファイルパスにスペースや特殊文字が含まれる場合は %%~F のクォート処理が崩れることがあります。その場合は PowerShell スクリプト単体で実装することをお勧めします。
@echo off
setlocal enabledelayedexpansion

set "SRC=C:\app\logs"
set "DST_BASE=C:\app\logs\archive"

if not exist "%DST_BASE%" mkdir "%DST_BASE%"

set /a MOVED=0

rem 30日以上前の .log ファイルを月別フォルダへ移動
for /f "usebackq tokens=*" %%F in (`forfiles /p "%SRC%" /m *.log /d -30 /c "cmd /c echo @path"`) do (
    rem ファイル更新年月を取得(PowerShell 経由)
    for /f "usebackq tokens=*" %%M in (`powershell -NoProfile -Command "(Get-Item '%%~F').LastWriteTime.ToString('yyyyMM')"`) do (
        set "MONTH=%%M"
    )
    set "DST=%DST_BASE%\!MONTH!"
    if not exist "!DST!" mkdir "!DST!"
    move "%%~F" "!DST!\"
    set /a MOVED+=1
)

echo 古いログ移動完了: %MOVED% 件
endlocal

実践例C: ビルド成果物を種別フォルダに振り分けて移動

ビルドフォルダに混在する .exe.dll.pdb をそれぞれの種別フォルダに振り分け、整理します。

@echo off
setlocal enabledelayedexpansion

set "SRC=C:\build\output"
set "DST_BASE=C:\release"

rem 種別ごとに移動先フォルダを定義
set "DST_EXE=%DST_BASE%\bin"
set "DST_DLL=%DST_BASE%\lib"
set "DST_PDB=%DST_BASE%\symbols"

for %%D in ("%DST_EXE%" "%DST_DLL%" "%DST_PDB%") do (
    if not exist %%D mkdir %%D
)

move "%SRC%\*.exe" "%DST_EXE%\"
move "%SRC%\*.dll" "%DST_DLL%\"
move "%SRC%\*.pdb" "%DST_PDB%\"

echo ビルド成果物の振り分け完了
echo   exe → %DST_EXE%
echo   dll → %DST_DLL%
echo   pdb → %DST_PDB%
endlocal

よくある落とし穴

落とし穴1: 移動先に同名ファイルがあると確認なしに上書き

move は移動先に同名ファイルがあるとき、確認ダイアログなしで上書きします。上書きを防ぐには事前に存在チェックを入れるか、robocopy /XO(古いものだけ移動)を使います。

@echo off
setlocal enabledelayedexpansion

set "SRC=C:\src"
set "DST=C:\dst"

for %%F in ("%SRC%\*.txt") do (
    if exist "%DST%\%%~nxF" (
        echo [SKIP] %%~nxF は移動先に存在するためスキップ
    ) else (
        move "%%F" "%DST%\"
    )
)
endlocal

落とし穴2: move はサブフォルダを再帰的に処理しない

move *.txt dest\ はカレントフォルダのファイルのみ対象です。サブフォルダも含めて移動するには for /rrobocopy /S を使います。

rem NG: サブフォルダは処理されない
move "C:\src\*.txt" "C:\dst\"

rem OK: for /r でサブフォルダを再帰処理
for /r "C:\src" %%F in (*.txt) do move "%%F" "C:\dst\"

落とし穴3: パスにスペースが含まれるとエラー

フォルダ名やファイル名にスペースがある場合、move の引数を " " で囲まないとエラーになります。ワイルドカードも含めて常にダブルクォートで囲む習慣を付けましょう。

rem NG: スペースがあるパスはエラー
move C:\My Documents\*.txt C:\Archive\

rem OK: ダブルクォートで囲む
move "C:\My Documents\*.txt" "C:\Archive\"

落とし穴4: 移動先フォルダが存在しないとエラー

move は移動先フォルダが存在しない場合エラーになります。if not exist ... mkdir で事前に作成してください。

@echo off

set "DST=C:\archive\2024"

rem フォルダがなければ作成してから移動
if not exist "%DST%" mkdir "%DST%"
move "C:\work\*.bak" "%DST%\"

落とし穴5: ? は1文字にのみマッチ・パスセパレータをまたがない

? は必ず1文字にマッチします。file?.txtfile1.txt(1文字)にはマッチしますが、file12.txt(2文字)にはマッチしません。また ? は拡張子の . もパスセパレータ(\)も「1文字」としてカウントされるため、拡張子パターンの組み合わせに注意が必要です。*.txt* もパスセパレータをまたがず、カレントフォルダ内のみが対象です。サブフォルダは for /r で対応します。

rem file?.txt は file1.txt にマッチ、file12.txt にはマッチしない
move "C:\data\file?.txt" "C:\done\"

rem *.* は拡張子を持つファイル全て
move "C:\data\*.*" "C:\done\"

rem * だけだと拡張子なしファイルもマッチ(*.* との違いに注意)
move "C:\data\*" "C:\done\"

よくある質問(FAQ)

Q 移動したファイルの件数を確認したい
A

for ループでカウンタを使うか、robocopy のサマリーを利用します。

@echo off
setlocal enabledelayedexpansion

set /a COUNT=0

for %%F in ("C:\src\*.txt") do (
    move "%%F" "C:\dst\"
    set /a COUNT+=1
)

echo 移動完了: !COUNT! 件
endlocal
Q 移動対象がなくてもエラーにしたくない
A

move コマンドは対象ファイルがない場合に”ファイルが見つかりません”を表示してエラーレベルを返します。for ループを使えば対象ゼロでも何も起きません。

@echo off
setlocal enabledelayedexpansion

set /a COUNT=0

for %%F in ("C:\src\*.tmp") do (
    move "%%F" "C:\dst\" >nul
    set /a COUNT+=1
)

if !COUNT!==0 (
    echo 移動対象のファイルはありませんでした
) else (
    echo !COUNT! 件移動しました
)
endlocal
Q 移動後にログファイルを残したい
A

移動したファイル名と日時を別ファイルに記録します。

@echo off
setlocal enabledelayedexpansion

set "SRC=C:\src"
set "DST=C:\dst"
set "LOG=move_log.txt"

for %%F in ("%SRC%\*.log") do (
    move "%%F" "%DST%\"
    echo %DATE% %TIME% MOVED %%~nxF >> "%LOG%"
)

echo ログ: %LOG%
endlocal
Q 別ドライブへの移動が遅い
A

同一ドライブ内の move はディレクトリエントリの変更だけで完了するため高速ですが、別ドライブへの移動は実際にファイルをコピーしてから削除するため時間がかかります。これは正常な動作です。大量ファイルの別ドライブ移動には robocopy /MOV /MT(マルチスレッド)が高速です。

rem マルチスレッド(/MT:8)で別ドライブへ高速移動
robocopy "C:\src" "D:\dst" *.* /MOV /MT:8 /NFL /NDL
Q 移動先のファイル名を変えながら移動したい
A

move は移動と同時にリネームもできます。ただしワイルドカードを使いながらリネームする場合、同名の場合は上書きになる点に注意です。

@echo off
setlocal enabledelayedexpansion

rem ファイルを移動しながらプレフィックスを付けてリネーム
for %%F in ("C:\src\*.txt") do (
    move "%%F" "C:\dst\archive_%%~nxF"
)

echo 移動・リネーム完了
endlocal
Q 読み取り専用ファイルが含まれると move が失敗する
A

読み取り専用属性が付いているファイルは move でエラーになることがあります。attrib -r で属性を解除してから移動してください。

@echo off
setlocal

set "SRC=C:\src"
set "DST=C:\dst"

rem 読み取り専用属性を解除してから移動
attrib -r "%SRC%\*.bak"
move "%SRC%\*.bak" "%DST%\"

echo 完了
endlocal

まとめ

目的 推奨方法 ポイント
拡張子指定で一括移動 move “src\*.ext” “dst\” シンプル・同一ドライブなら高速
ファイル名パターンで移動 move “prefix_*.*” / “file????.csv” * と ? を組み合わせて柔軟に絞り込み
サブフォルダ再帰移動 for /r + move move 単体はサブフォルダ非対応
安全な移動(上書き制御) robocopy /MOV /XO コピー後削除・上書きスキップ対応
実行前の確認 for + echo(ドライラン)/ robocopy /L 本番前に必ず確認
別ドライブへの大量移動 robocopy /MOV /MT:8 マルチスレッドで高速化

単発の移動なら move、サブフォルダ・大量ファイル・上書き制御が必要なら robocopy /MOV を選ぶのが基本方針です。本番実行前は必ずドライランで対象を確認しましょう。

ファイルの拡張子を一括で変更するには bat でファイルの拡張子を一括変換する方法 を、特定の文字列を含むファイルを別フォルダにコピーするには bat で特定の文字列を含むファイルをコピーする方法 も合わせて参照してください。