【bat】特定の文字列を含むファイルを別フォルダにコピーする方法完全ガイド|ファイル名・内容検索・findstr・複数条件・robocopy・実践パターンまで

【bat】特定の文字列を含むファイルを別フォルダにコピーする方法完全ガイド|ファイル名・内容検索・findstr・複数条件・robocopy・実践パターンまで bat

「エラーログだけ別フォルダに集めたい」「ファイル名にプロジェクト名を含むファイルをまとめてコピーしたい」——バッチファイルで文字列フィルタリングを使ったファイルコピーは自動化の定番です。本記事では ファイル名による絞り込みファイル内容による絞り込みfindstr)の2軸を中心に、AND/OR複数条件・フォルダ構造維持・robocopy連携・実践パターンまで体系的に解説します。

この記事で解決できること

  • ファイル名に特定の文字列を含むファイルだけをコピーする方法
  • ファイルの中身に特定の文字列を含むファイルだけをコピーする方法(findstr /m
  • 複数キーワードの AND 条件・OR 条件でフィルタリングする方法
  • サブフォルダのフォルダ構造を維持したままコピーする方法
  • コピー件数・コピーログを記録して安全に運用するパターン
  • 日本語ファイル名・日本語内容の検索における注意点
スポンサーリンク

方法の比較

検索対象 方法 特徴
ファイル名(前方・後方一致) for /r %%F in (*keyword*) シンプル・高速
ファイル名(完全パターン) for /f + dir /b findstr で柔軟に絞り込み
ファイルの中身(1キーワード) findstr /m /l "keyword" *.log 内容検索・ファイル名リスト出力
ファイルの中身(AND 条件) findstr /m を2回パイプ 全キーワードを含む
ファイルの中身(OR 条件) findstr /m /c:"kw1" /c:"kw2" いずれかを含む
ファイル名+拡張子パターン robocopy + /if *.pattern フォルダ構造維持・大量ファイル向け

方法1: ファイル名に文字列を含むファイルをコピー

基本: ワイルドカードで絞り込んでコピー

@echo off
setlocal enabledelayedexpansion

set KEYWORD=error
set SRC=C:worklogs
set DST=C:workfiltered

rem コピー先フォルダを作成
if not exist "%DST%" mkdir "%DST%"

rem ファイル名に KEYWORD を含むファイルを再帰的にコピー
for /r "%SRC%" %%F in (*%KEYWORD%*) do (
    echo コピー: %%~nxF
    copy "%%~fF" "%DST%" >nul
)

echo 完了
endlocal

特定の拡張子に限定してコピー

@echo off
setlocal

set KEYWORD=error
set SRC=C:worklogs
set DST=C:workfiltered

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

rem "error" を含む .log ファイルのみコピー
for /r "%SRC%" %%F in (*%KEYWORD%*.log) do (
    echo コピー: %%~nxF
    copy "%%~fF" "%DST%" >nul
)

endlocal

直下のみ(再帰なし)コピー

@echo off
setlocal

set KEYWORD=report
set SRC=C:worklogs
set DST=C:workfiltered

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

rem SRC 直下のみ対象(for /r なしで for を使う)
for %%F in ("%SRC%*%KEYWORD%*") do (
    copy "%%~fF" "%DST%" >nul
    echo コピー: %%~nxF
)

endlocal

方法2: ファイルの中身に文字列を含むファイルをコピー

findstr /m(マッチしたファイル名のみ出力)を使って、内容に特定文字列を含むファイルを絞り込み、for /f でループしてコピーします。

基本: 内容に文字列を含むファイルをコピー(直下のみ)

@echo off
setlocal

set KEYWORD=ERROR
set SRC=C:worklogs
set DST=C:workfiltered

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

rem /m = ファイル名のみ出力  /i = 大文字小文字無視  /l = リテラル検索
for /f "delims=" %%F in ('findstr /m /i /l "%KEYWORD%" "%SRC%*.log"') do (
    echo コピー: %%~nxF
    copy "%%F" "%DST%" >nul
)

echo 完了
endlocal

サブフォルダも再帰的に検索してコピー

@echo off
setlocal enabledelayedexpansion

set KEYWORD=CRITICAL
set SRC=C:worklogs
set DST=C:workfiltered

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

set COUNT=0

rem /s = サブフォルダも対象  /m = ファイル名のみ出力
for /f "delims=" %%F in ('findstr /s /m /i /l "%KEYWORD%" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
    if not errorlevel 1 (
        echo コピー: %%F
        set /a COUNT+=1
    )
)

echo.
echo 完了: !COUNT! ファイルをコピーしました
endlocal
findstr /m の主なオプション
/m = マッチしたファイル名のみ出力(コピー処理に最適)
/i = 大文字小文字を区別しない
/l = 文字列をリテラル(正規表現なし)で検索
/s = サブフォルダも再帰的に検索
/c:"str" = 複数条件を OR で指定(後述)

方法3: 複数キーワードで絞り込む

OR 条件(いずれかの文字列を含む)

@echo off
setlocal enabledelayedexpansion

set SRC=C:worklogs
set DST=C:workfiltered

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

set COUNT=0

rem /c:"kw1" /c:"kw2" は OR 条件(どちらかを含むファイルを出力)
for /f "delims=" %%F in ('findstr /s /m /i /l /c:"ERROR" /c:"CRITICAL" /c:"FATAL" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
    if not errorlevel 1 (
        echo コピー: %%~nxF
        set /a COUNT+=1
    )
)

echo 完了: !COUNT! ファイル
endlocal

AND 条件(全ての文字列を含む)

@echo off
setlocal enabledelayedexpansion

set SRC=C:worklogs
set DST=C:workfiltered

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

set COUNT=0

rem AND 条件: キーワード1 AND キーワード2 の両方を含むファイルをコピー
rem 手順: findstr で kw1 にマッチしたファイルリストを取得
rem        → そのファイルに対して再度 findstr で kw2 を確認
for /f "delims=" %%F in ('findstr /s /m /i /l /c:"ERROR" "%SRC%*.log"') do (
    rem 同じファイルに kw2 も含まれているか確認
    findstr /i /l /c:"Database" "%%F" >nul 2>&1
    if not errorlevel 1 (
        copy "%%F" "%DST%" >nul
        echo コピー(AND一致): %%~nxF
        set /a COUNT+=1
    )
)

echo 完了: !COUNT! ファイル
endlocal

除外条件(文字列を含まないファイルをコピー)

@echo off
setlocal enabledelayedexpansion

set SRC=C:worklogs
set DST=C:workfiltered

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

set COUNT=0

rem "DEBUG" を含まない .log ファイルだけコピー
for %%F in ("%SRC%*.log") do (
    rem findstr がマッチしない (errorlevel 1) ものをコピー対象にする
    findstr /i /l /c:"DEBUG" "%%F" >nul 2>&1
    if errorlevel 1 (
        copy "%%~fF" "%DST%" >nul
        echo コピー(除外一致): %%~nxF
        set /a COUNT+=1
    )
)

echo 完了: !COUNT! ファイル
endlocal

findstr の詳しい使い方は FINDSTRコマンドの使い方完全ガイド を参照してください。

フォルダ構造を維持してコピーする

単純な copy はファイルをフラットにコピーします。サブフォルダの構造を保ったままコピーするには xcopy /s または robocopy を使います。

xcopy でフォルダ構造を維持

@echo off
setlocal enabledelayedexpansion

set KEYWORD=error
set SRC=C:worklogs
set DST=C:workfiltered

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

rem xcopy /s = サブフォルダも含む  /i = コピー先がフォルダと認識  /y = 上書き確認なし
for /r "%SRC%" %%F in (*%KEYWORD%*.log) do (
    rem %%~dpF = ファイルのディレクトリパス(フォルダ構造を維持するために使用)
    set REL_PATH=%%~dpF
    set REL_PATH=!REL_PATH:%SRC%=!
    set DST_SUB=%DST%!REL_PATH!
    if not exist "!DST_SUB!" mkdir "!DST_SUB!"
    copy "%%~fF" "!DST_SUB!" >nul
    echo コピー: %%~nxF → !DST_SUB!
)

endlocal

robocopy でファイル名パターンを指定してコピー

@echo off
setlocal

set SRC=C:worklogs
set DST=C:workfiltered

rem robocopy でファイル名パターンを指定してサブフォルダごとコピー
rem /s = サブフォルダも対象  /r:2 = リトライ2回  /w:5 = 待機5秒
robocopy "%SRC%" "%DST%" *error*.log /s /r:2 /w:5 /log+:"%DST%
obocopy.log"

rem robocopy の終了コード(0-7 は正常)
if errorlevel 8 (
    echo [ERROR] コピーでエラーが発生しました
) else (
    echo [OK] コピー完了
)

endlocal

robocopy の詳細は ROBOCOPYの使い方完全ガイド を参照してください。

実践例A: エラーログ収集スクリプト

複数のサービスのログフォルダから「ERROR」または「CRITICAL」を含むファイルを1か所に集めるパターンです。

@echo off
setlocal enabledelayedexpansion

set LOG_ROOT=C:worklogs
set COLLECT=C:workfilterederror_logs_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%

if not exist "%COLLECT%" mkdir "%COLLECT%"

echo === エラーログ収集開始: %DATE% %TIME% ===

set TOTAL=0

rem ERROR または CRITICAL を含む .log ファイルを収集
for /f "delims=" %%F in ('findstr /s /m /i /l /c:"ERROR" /c:"CRITICAL" "%LOG_ROOT%*.log"') do (
    copy "%%F" "%COLLECT%" >nul
    if not errorlevel 1 (
        echo 収集: %%~nxF (%%~dpF)
        set /a TOTAL+=1
    )
)

echo.
echo === 収集完了: !TOTAL! ファイル → %COLLECT% ===
endlocal

実践例B: ファイル名にプロジェクト名を含むファイルを収集

@echo off
setlocal enabledelayedexpansion

set PROJECT=ProjectAlpha
set SRC=C:worksource
set DST=C:workdest\%PROJECT%

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

set COUNT=0

rem ファイル名にプロジェクト名を含む全ファイルをコピー
for /r "%SRC%" %%F in (*%PROJECT%*) do (
    copy "%%~fF" "%DST%" >nul
    if not errorlevel 1 (
        echo コピー: %%~nxF
        set /a COUNT+=1
    )
)

echo 完了: !COUNT! ファイルを %DST% にコピーしました
endlocal

実践例C: コピー結果を CSV ログに記録する

@echo off
setlocal enabledelayedexpansion

set KEYWORD=ERROR
set SRC=C:worklogs
set DST=C:workfiltered
set CSVLOG=%~dp0copy_log.csv

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

rem CSV ヘッダー(初回のみ)
if not exist "%CSVLOG%" (
    echo 日時,ファイル名,元パス,コピー先,結果 > "%CSVLOG%"
)

for /f "delims=" %%F in ('findstr /s /m /i /l "%KEYWORD%" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
    if not errorlevel 1 (
        set RESULT=OK
    ) else (
        set RESULT=FAIL
    )
    echo %DATE% %TIME%,%%~nxF,%%~dpF,%DST%,!RESULT! >> "%CSVLOG%"
    echo !RESULT!: %%~nxF
)

endlocal

よくある落とし穴

落とし穴1: ワイルドカードはファイルの「中身」を検索しない

rem NG: for /r %%F in (*error*) はファイル名に "error" を含むファイルを対象にする
rem     ファイルの中身に "error" を含むかどうかは関係ない!
for /r "%SRC%" %%F in (*error*) do (
    copy "%%F" "%DST%" >nul
)

rem ファイルの中身で検索するには findstr /m を使う
for /f "delims=" %%F in ('findstr /s /m /i /l "error" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
)

落とし穴2: findstr の日本語(マルチバイト文字)は正しく動作しない場合がある

rem findstr は ASCII テキストを前提としている
rem UTF-8 や Shift-JIS の日本語文字列は findstr で正しく検索できない場合がある

rem 日本語を含むファイルを検索する場合は PowerShell を使う
powershell -NoProfile -Command ^
"Get-ChildItem -Path '%SRC%' -Filter *.log -Recurse |" ^
"Where-Object { (Get-Content $_.FullName -Encoding UTF8 -ErrorAction SilentlyContinue) -match 'エラー' } |" ^
"ForEach-Object { Copy-Item $_.FullName -Destination '%DST%' -Force }"

落とし穴3: copy はフォルダ構造を維持しない

rem copy は常に指定フォルダへフラットにコピーする
rem → サブフォルダ構造が失われ、同名ファイルが上書きされる可能性がある

rem OK: フォルダ構造を維持したい場合は xcopy /s または robocopy を使う
xcopy "%%~fF" "%DST%\%%~pF" /i /y /s >nul

rem または robocopy
robocopy "%SRC%" "%DST%" *error*.log /s /r:2 /w:5

落とし穴4: パスにスペースがある場合のクォート

rem NG: パスにスペースがあるとファイルが見つからない
for /f "delims=" %%F in ('findstr /m /i "ERROR" C:My Logs*.log') do (
    copy %%F C:dest
)

rem OK: パスをダブルクォートで囲む
for /f "delims=" %%F in ('findstr /m /i "ERROR" "C:My Logs*.log"') do (
    copy "%%F" "C:dest" >nul
)

落とし穴5: for /r は変数のパスを展開しない場合がある

rem NG: %KEYWORD% の値が空だとワイルドカードが意図通りに機能しない
set KEYWORD=
for /r "%SRC%" %%F in (**) do ...   ← 全ファイルが対象になってしまう

rem 変数が空でないことを確認する
if "%KEYWORD%"=="" (
    echo [ERROR] KEYWORD が設定されていません
    exit /b 1
)

for /r "%SRC%" %%F in (*%KEYWORD%*) do ...

よくある質問(FAQ)

Q 大文字小文字を区別して検索したい
A

findstr/i を付けると大文字小文字を区別しません。区別する場合は /i を外します。

rem 大文字小文字を区別する(/i なし)
for /f "delims=" %%F in ('findstr /s /m /l "ERROR" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
)

rem 大文字小文字を区別しない(/i あり)
for /f "delims=" %%F in ('findstr /s /m /i /l "error" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
)
Q コピー先に同名ファイルがある場合に上書きしたくない
A

コピー前に if not exist で確認するか、xcopy /-y(確認あり)を使います。

@echo off
setlocal

set SRC=C:worklogs
set DST=C:workfiltered

for /f "delims=" %%F in ('findstr /s /m /i /l "ERROR" "%SRC%*.log"') do (
    rem 移動先に同名ファイルがなければコピー
    if not exist "%DST%\%%~nxF" (
        copy "%%F" "%DST%" >nul
        echo コピー: %%~nxF
    ) else (
        echo スキップ(既存): %%~nxF
    )
)

endlocal
Q 正規表現でファイルの内容を検索したい
A

findstr は基本的な正規表現をサポートしています(/r オプション)。ただし完全な正規表現ではないため、複雑なパターンは PowerShell の -match 演算子を使うのが確実です。

rem findstr の正規表現(/r オプション)
rem 例: "ERROR:" または "WARN:" で始まる行を含むファイルを検索
for /f "delims=" %%F in ('findstr /s /m /r /c:"^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*ERROR" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
    echo コピー: %%~nxF
)
Q コピーしたファイルの件数を確認したい
A

enabledelayedexpansion を使ってループ内でカウンタを更新します。

@echo off
setlocal enabledelayedexpansion

set SRC=C:worklogs
set DST=C:workfiltered
set COUNT=0

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

for /f "delims=" %%F in ('findstr /s /m /i /l "ERROR" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
    if not errorlevel 1 set /a COUNT+=1
)

echo コピー完了: !COUNT! ファイル
endlocal
Q コピー元ファイルを移動(コピー後に削除)したい
A

コピー後に del で元ファイルを削除します。

@echo off
setlocal

set SRC=C:worklogs
set DST=C:workfiltered

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

for /f "delims=" %%F in ('findstr /s /m /i /l "ERROR" "%SRC%*.log"') do (
    copy "%%F" "%DST%" >nul
    if not errorlevel 1 (
        del /Q "%%F"
        echo 移動完了: %%~nxF
    ) else (
        echo [FAIL] コピー失敗(削除しません): %%~nxF
    )
)

endlocal

ファイルの移動については ファイルを別フォルダに移動する方法完全ガイド も参照してください。

まとめ

目的 推奨方法
ファイル名にキーワードを含む→コピー for /r %%F in (*keyword*) do copy
ファイル内容にキーワードを含む→コピー findstr /s /m /i /l "kw" + for /f + copy
OR 条件(いずれかを含む) findstr /c:"kw1" /c:"kw2"
AND 条件(全てを含む) findstr を2回適用
除外条件(含まないファイルのみ) findstrerrorlevel 1 の場合にコピー
フォルダ構造を維持してコピー robocopy /s またはパス操作で xcopy
コピー後に元ファイルを削除(移動) コピー成功後に del
日本語テキストを検索 PowerShell Get-Content + -match

文字列検索の詳細は FINDSTRコマンドの使い方完全ガイド を、ファイルの削除は ファイルを削除する方法完全ガイド を、複数フォルダのループ処理は 複数フォルダをループして一括処理する方法 も合わせて参照してください。