「エラーログだけ別フォルダに集めたい」「ファイル名にプロジェクト名を含むファイルをまとめてコピーしたい」——バッチファイルで文字列フィルタリングを使ったファイルコピーは自動化の定番です。本記事では ファイル名による絞り込み と ファイル内容による絞り込み(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
/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)
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
)
コピー前に 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
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
)
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
コピー後に 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回適用 |
| 除外条件(含まないファイルのみ) | findstr が errorlevel 1 の場合にコピー |
| フォルダ構造を維持してコピー | robocopy /s またはパス操作で xcopy |
| コピー後に元ファイルを削除(移動) | コピー成功後に del |
| 日本語テキストを検索 | PowerShell Get-Content + -match |
文字列検索の詳細は FINDSTRコマンドの使い方完全ガイド を、ファイルの削除は ファイルを削除する方法完全ガイド を、複数フォルダのループ処理は 複数フォルダをループして一括処理する方法 も合わせて参照してください。

