【bat】バッチファイルで実行ログを出力する方法

【bat】バッチファイルで実行ログを出力する方法 bat

バッチファイルの実行ログをファイルに出力する方法を解説します。

ログを残しておけば、いつ・何が実行され・成功したか失敗したかを後から確認できます。この記事では、基本的なリダイレクトから、日時スタンプ付きログ画面とファイルへの同時出力ログ関数の作り方古いログの自動削除まで、実務で使えるログ出力の方法を網羅的に解説します。

スポンサーリンク

基本:リダイレクトでログファイルに出力する

>(上書き)と >>(追記)でコマンドの出力をファイルに保存できます。

@echo off
rem 上書き(ファイルを新規作成 or 既存の内容を消して書き込み)
echo 処理を開始します > C:\logs\output.log

rem 追記(既存の内容の末尾に追加)
echo ファイルをコピーしました >> C:\logs\output.log
echo 処理が完了しました >> C:\logs\output.log
記号 動作 用途
> 上書き 毎回新しいログを作成する場合
>> 追記 既存のログに追加する場合(通常はこちら)

標準エラー出力もログに含める

> だけではエラーメッセージがログに残りません。エラー出力も含めるには 2>&1 を追加します。

@echo off
rem 標準出力だけログに保存(エラーは画面に表示される)
xcopy C:\data\*.* C:\backup\ /E /Y >> log.txt

rem 標準出力+エラー出力の両方をログに保存
xcopy C:\data\*.* C:\backup\ /E /Y >> log.txt 2>&1

2>&1 は「標準エラー出力(2)を標準出力(1)にマージする」という意味です。リダイレクトの詳細は「標準出力と標準エラーをリダイレクトする方法」をご覧ください。

エラーだけ別ファイルに分離する

@echo off
rem 標準出力 → output.log、エラー出力 → error.log
xcopy C:\data\*.* C:\backup\ /E /Y >> output.log 2>> error.log

エラーが発生したときだけ error.log を確認すればよいので、大量のログから問題を見つけやすくなります。

日時スタンプ付きでログを出力する

いつ実行されたかを記録するには、%date%%time% を使います。

@echo off
set LOGFILE=C:\logs\batch.log

echo [%date% %time%] === 処理開始 === >> "%LOGFILE%"
echo [%date% %time%] ファイルコピー開始 >> "%LOGFILE%"

xcopy C:\data\*.* C:\backup\ /E /Y >> "%LOGFILE%" 2>&1

echo [%date% %time%] ファイルコピー完了 >> "%LOGFILE%" 2>&1
echo [%date% %time%] === 処理終了 === >> "%LOGFILE%"

出力例

[2026/03/04 10:30:15.42] === 処理開始 ===
[2026/03/04 10:30:15.43] ファイルコピー開始
      5 個のファイルをコピーしました
[2026/03/04 10:30:16.01] ファイルコピー完了
[2026/03/04 10:30:16.02] === 処理終了 ===

日付ごとにログファイルを分ける

毎日実行するバッチファイルでは、日付ごとにログファイルを分けると管理しやすくなります。

@echo off
rem 日付からファイル名を生成(例: batch_20260304.log)
set LOGFILE=C:\logs\batch_%date:~0,4%%date:~5,2%%date:~8,2%.log

echo [%date% %time%] 処理開始 >> "%LOGFILE%"

rem 処理...

echo [%date% %time%] 処理終了 >> "%LOGFILE%"

%date:~0,4% で年、%date:~5,2% で月、%date:~8,2% で日を取得しています。日付の取得方法の詳細は「バッチファイルで日付や時間を取得する方法」をご覧ください。

バッチ全体の出力をまとめてログに保存する

個別に >> を書くのが面倒な場合、括弧でバッチ全体を囲んで一括リダイレクトできます。

@echo off
(
    echo [%date% %time%] === 処理開始 ===
    echo ファイルをコピーします。
    xcopy C:\data\*.* C:\backup\ /E /Y
    echo 古いファイルを削除します。
    forfiles /P C:\backup /M *.tmp /D -7 /C "cmd /c del @path" 2>nul
    echo [%date% %time%] === 処理終了 ===
) >> C:\logs\batch.log 2>&1

括弧内のすべての出力(echo も xcopy の結果も)が batch.log に追記されます。各行に >> を書く必要がないため、コードがスッキリします。

画面とログファイルに同時出力する

ログをファイルに保存しつつ、画面にも表示したい場合があります。

方法1:ログ関数を作る(推奨)

@echo off
set LOGFILE=C:\logs\batch.log

call :log "=== 処理開始 ==="
call :log "ファイルをコピーします。"
xcopy C:\data\*.* C:\backup\ /E /Y >> "%LOGFILE%" 2>&1
call :log "処理が完了しました。"
pause
exit /b

:log
set MSG=[%date% %time%] %~1
echo %MSG%
echo %MSG% >> "%LOGFILE%"
exit /b

:log サブルーチンが echo(画面表示)と >>(ファイル出力)の両方を行います。ログを出すたびに call :log "メッセージ" と書くだけでOKです。

サブルーチンの詳しい使い方は「バッチファイルでサブルーチンを作成する方法」をご覧ください。

方法2:バッチ全体をパイプで tee する

@echo off
rem PowerShell の Tee-Object を利用
powershell -Command "cmd /c C:\scripts\main.bat | Tee-Object -FilePath C:\logs\batch.log"

この方法はバッチの中身を変更する必要がなく、外部からログを取得できます。ただし PowerShell の起動分だけ遅くなります。

ログにレベル(INFO / ERROR)を付ける

ログにレベルを付けると、エラーの発見が容易になります。

@echo off
set LOGFILE=C:\logs\batch.log

call :log INFO "=== 日次バッチ開始 ==="
call :log INFO "ファイルコピーを実行します。"

xcopy C:\data\*.* C:\backup\ /E /Y >> "%LOGFILE%" 2>&1
if %ERRORLEVEL% neq 0 (
    call :log ERROR "ファイルコピーに失敗しました。code=%ERRORLEVEL%"
    goto :finally
)
call :log INFO "ファイルコピー完了"

call :log INFO "=== 日次バッチ正常終了 ==="
goto :finally

:finally
pause
exit /b

:log
set LEVEL=%1
set MSG=%~2
echo [%date% %time%] [%LEVEL%] %MSG%
echo [%date% %time%] [%LEVEL%] %MSG% >> "%LOGFILE%"
exit /b

出力例

[2026/03/04 10:30:15.42] [INFO] === 日次バッチ開始 ===
[2026/03/04 10:30:15.43] [INFO] ファイルコピーを実行します。
[2026/03/04 10:30:16.01] [INFO] ファイルコピー完了
[2026/03/04 10:30:16.02] [INFO] === 日次バッチ正常終了 ===

エラー発生時のログ:

[2026/03/04 10:30:15.42] [INFO] === 日次バッチ開始 ===
[2026/03/04 10:30:15.43] [INFO] ファイルコピーを実行します。
[2026/03/04 10:30:16.01] [ERROR] ファイルコピーに失敗しました。code=4

[ERROR] で検索すれば、大量のログの中からエラー行だけをすぐに見つけられます。

古いログファイルを自動削除する

ログが溜まり続けるとディスクを圧迫します。forfiles コマンドで一定期間より古いログを自動削除しましょう。

@echo off
rem 30日より古いログを削除
forfiles /P C:\logs /M *.log /D -30 /C "cmd /c echo 削除: @path && del @path" 2>nul
オプション 意味
/P 検索するフォルダ
/M *.log .log ファイルを対象
/D -30 30日より古いファイル
/C "..." 対象ファイルに実行するコマンド

バッチの先頭でこの処理を入れておけば、実行するたびに古いログが自動的にクリーンアップされます。

実務テンプレート:ログ出力付きバッチの雛形

@echo off
setlocal

rem === 設定 ===
set LOGDIR=%~dp0logs
set LOGFILE=%LOGDIR%\batch_%date:~0,4%%date:~5,2%%date:~8,2%.log

rem ログフォルダ作成
if not exist "%LOGDIR%" mkdir "%LOGDIR%"

rem 古いログを削除(30日以上)
forfiles /P "%LOGDIR%" /M *.log /D -30 /C "cmd /c del @path" 2>nul

call :log INFO "======================================"
call :log INFO "バッチ処理開始"
call :log INFO "実行ユーザー: %USERNAME%"
call :log INFO "======================================"

rem --- ステップ1: ファイルコピー ---
call :log INFO "ステップ1: ファイルコピー開始"
xcopy C:\data\*.csv C:\backup\ /E /Y >> "%LOGFILE%" 2>&1
if %ERRORLEVEL% neq 0 (
    call :log ERROR "ステップ1: ファイルコピー失敗 [code=%ERRORLEVEL%]"
    goto :finally
)
call :log INFO "ステップ1: ファイルコピー完了"

rem --- ステップ2: データ集計 ---
call :log INFO "ステップ2: データ集計開始"
cscript //nologo C:\scripts\aggregate.vbs >> "%LOGFILE%" 2>&1
if %ERRORLEVEL% neq 0 (
    call :log ERROR "ステップ2: データ集計失敗 [code=%ERRORLEVEL%]"
    goto :finally
)
call :log INFO "ステップ2: データ集計完了"

call :log INFO "全処理正常終了"

:finally
call :log INFO "======================================"
endlocal
exit /b

rem === ログ出力関数 ===
:log
set LVL=%1
set MSG=%~2
echo [%date% %time%] [%LVL%] %MSG%
echo [%date% %time%] [%LVL%] %MSG% >> "%LOGFILE%"
exit /b

このテンプレートには以下の機能が含まれています。

  • 日付ごとのログファイル自動生成
  • 古いログの自動削除(30日以上)
  • INFO / ERROR のログレベル
  • 画面とファイルへの同時出力
  • ERRORLEVELによるエラーハンドリング
  • :finally ラベルで確実に後処理を実行

まとめ

やりたいこと 書き方
出力をログに保存 コマンド >> log.txt
エラーも含めて保存 コマンド >> log.txt 2>&1
日時を付ける echo [%date% %time%] メッセージ >> log.txt
日付別のログファイル set LOGFILE=batch_%date:~0,4%%date:~5,2%%date:~8,2%.log
画面+ファイル同時出力 call :log サブルーチンを使う
ログレベルを付ける call :log INFO "メッセージ"
古いログを自動削除 forfiles /P ... /D -30 /C "cmd /c del @path"

ポイント

  • >>(追記)を使い、>(上書き)は初回のみにする
  • エラー出力を含めるには 2>&1 を忘れずに付ける
  • 日時スタンプは必ず入れる(いつ実行されたかが分からないログは役に立たない)
  • ログ関数(:log)を用意すると、画面表示とファイル出力を一元管理できる
  • ログは溜まるので forfiles で定期的に削除する仕組みを入れておく

あわせて読みたい