1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【バッチファイルだけで簡易バックアップ】同名・同更新日のファイルをスキップしてバックアップする仕組みを作ってみた

1
Last updated at Posted at 2025-12-05

Windows のフォルダをサクッとバックアップしたいけど、
「前と同じファイルまで毎回コピーされるのはイヤ…」
「差分バックアップほど大げさじゃなくていい…」
そんなニーズ、ありませんか?

この記事では バッチファイル(.bat)だけで実装できる、
「同名かつ同じ更新日時のファイルが backup フォルダに存在する場合はスキップ」
という 簡易バックアップ機能を紹介します。

余計なツールは不要、ダブルクリックで実行するだけ。
バックアップフォルダも自動生成され、スキップしか無かった回はフォルダも自動削除。

手軽さと、無駄コピーの削減を両立した便利スクリプトになっています。


■ 実現できること

このバッチファイルは以下を自動で行います:

  • .bat と同じ階層にある「全てのファイル」をバックアップ対象にする
  • backup\backYYYYMMDDHHmmss フォルダへコピー
  • backup 配下の 全てのサブフォルダを走査し
    • 同じファイル名+同じ更新日時 が既にある場合 → コピーしない(SKIP)
  • 1つもコピーされなかった場合は、今回作成した backYYYYMMDDHHmmss フォルダを自動削除
  • よって、バックアップフォルダに重複が蓄積しない

難しい設定は一切なし。
バックアップフォルダの差分管理を“自動で”やってくれる超簡易バックアップです。


■ 導入手順(超簡単)

  1. 適当な場所にテキストファイルを作成
  2. ファイル名を Backup.bat のように「.bat」で終わる形にする(拡張子を bat にする)
  3. メモ帳等で開き、中に以下のコードをそのまま貼り付けて保存
  4. バックアップしたいフォルダに .bat を置いてダブルクリックするだけ!
Backup.bat
@echo off
setlocal EnableExtensions EnableDelayedExpansion
chcp 65001 >nul

rem === このBATがあるフォルダ ===
set "BASE_DIR=%~dp0"

rem === backup フォルダと、新しいバックアップフォルダ ===
set "BACKUP_BASE=%BASE_DIR%backup"

rem バックアップ用タイムスタンプ(yyyyMMddHHmmss)を PowerShell で取得
for /f %%T in ('powershell -NoProfile -Command "(Get-Date).ToString(\"yyyyMMddHHmmss\")"') do set "BACKSTAMP=%%T"

set "BACKUP_DIR=%BACKUP_BASE%\back%BACKSTAMP%"

rem backup\ と backup\backYYYYMMDDHHmmss を作成
if not exist "%BACKUP_BASE%" mkdir "%BACKUP_BASE%"
if not exist "%BACKUP_DIR%" mkdir "%BACKUP_DIR%"

echo [*] バックアップ先: "%BACKUP_DIR%"
echo.

rem ==================================================
rem  backup フォルダ以下に既にあるファイルの
rem  「ファイル名|更新日時(yyyyMMddHHmmss)」一覧を作成
rem ==================================================

set "INDEX=%TEMP%\backup_index_%RANDOM%.tmp"
if exist "%INDEX%" del "%INDEX%" >nul 2>&1

if exist "%BACKUP_BASE%" (
    echo [*] 既存バックアップのインデックスを作成中...
    for /r "%BACKUP_BASE%" %%F in (*) do (
        rem 既存バックアップ内の各ファイルの更新日時取得
        for /f %%T in ('powershell -NoProfile -Command "(Get-Item \"%%~fF\").LastWriteTime.ToString(\"yyyyMMddHHmmss\")"') do (
            >>"%INDEX%" echo %%~nxF^|%%T
        )
    )
) else (
    rem backupフォルダが存在しない場合は空インデックス(全てコピー対象)
    type nul > "%INDEX%"
)

rem ==================================================
rem  BATと同じ階層のファイルだけをバックアップ対象にする
rem  (サブフォルダ内は対象外)
rem ==================================================

set /a TOTAL=0, COPIED=0, SKIPPED=0, ERROR=0

echo [*] バックアップ元: "%BASE_DIR%"
echo.

for %%F in ("%BASE_DIR%*") do (
    rem 自分自身のbatファイルは除外
    if /I not "%%~fF"=="%~f0" (
        rem ディレクトリは除外
        set "ATTR=%%~aF"
        if /I not "!ATTR:~0,1!"=="d" (
            set /a TOTAL+=1
            set "NAME=%%~nxF"

            rem 元ファイルの更新日時取得
            for /f %%T in ('powershell -NoProfile -Command "(Get-Item \"%%~fF\").LastWriteTime.ToString(\"yyyyMMddHHmmss\")"') do set "SRCTIME=%%T"

            rem backup配下に「同じファイル名+同じ更新日時」が存在するか確認
            set "SKIP=0"
            if exist "%INDEX%" (
                findstr /I /C:"!NAME!^|!SRCTIME!" "%INDEX%" >nul 2>&1
                if not errorlevel 1 (
                    set "SKIP=1"
                )
            )

            if "!SKIP!"=="1" (
                echo [SKIP] 既に同名・同更新日時のバックアップあり → "!NAME!"
                set /a SKIPPED+=1
            ) else (
                copy /Y "%%~fF" "%BACKUP_DIR%\" >nul
                if errorlevel 1 (
                    echo [!] コピー失敗 → "%%~fF"
                    set /a ERROR+=1
                ) else (
                    echo [OK ] バックアップ → "%BACKUP_DIR%\!NAME!"
                    set /a COPIED+=1
                )
            )
        )
    )
)

rem インデックス削除
if exist "%INDEX%" del "%INDEX%" >nul 2>&1

rem === 1件もコピーされなかった場合は、このバックアップフォルダを削除 ===
if "!COPIED!"=="0" (
    echo.
    echo [*] 1件もバックアップされなかったため、今回作成したフォルダを削除します: "%BACKUP_DIR%"
    rd "%BACKUP_DIR%" >nul 2>&1
)

echo.
echo ===== 結果 =====
echo   対象ファイル数: !TOTAL!
echo   バックアップ実施: !COPIED!
echo   既存と同一のためスキップ: !SKIPPED!
echo   エラー: !ERROR!
echo.
echo 何かキーを押すと閉じます...
pause >nul
endlocal

■ バックアップの流れを詳しく解説

1. backYYYYMMDDHHmmss フォルダを自動生成

実行するたびに、現在時刻を元にしたフォルダが作られるので、
「いつバックアップしたか」が一目で分かります。

例)
backup\back20251205162230

2. 既存バックアップのファイル一覧を作成

backup フォルダ以下にあるすべてのファイルを再帰的に調べ、
「ファイル名 | 更新日時(yyyyMMddHHmmss)」の一覧を一時ファイルに記録します。

これにより、

  • 日付フォルダが異なる
  • サブフォルダに入っている

といった場合でも 同じ内容かどうかを正確に判別できます。

3. バッチファイルと同階層のファイルを順にチェック

対象となるのは、

  • 同じ階層のファイルのみ
  • サブフォルダは対象外
  • バッチファイル自身は除外

選択の手間なく、フォルダに置くだけでバックアップ対象が決まります。

4. 同名・同更新日のファイルが既にある場合はスキップ

余計なファイルコピーが発生しません。
更新されていないファイルはすべて SKIP されます。

バックアップ先を無駄に増やさないので、
HDD/SSD の容量節約にも効果的です。

5. 全てスキップだった場合はフォルダを削除

「バックアップフォルダは作られたけど中身は空」という状態を回避するため、
コピー数が 0 の場合はフォルダを自動で削除します。

毎日のバックアップでもフォルダが散らからず便利!


■ 実行結果イメージ

[*] バックアップ先: backup\back20251205162230
[SKIP] 既に同名・同更新日時のバックアップあり → sample1.txt
[SKIP] 既に同名・同更新日時のバックアップあり → sample2.txt
[OK ] バックアップ → backup\back20251205162230\sample3.txt

===== 結果 =====
対象ファイル数: 3
バックアップ実施: 1
既存と同一のためスキップ: 2
エラー: 0

■ この方式のメリットまとめ

  • 設定不要。バッチファイルを置いて実行するだけ
  • バックアップが bat ファイルを起動するだけで取れる
  • 空バックアップが作られないためフォルダが散らからない
  • PowerShell や外部ツール不要(Windows 標準機能のみ)
  • サブフォルダも含めて比較するため精度が高い

「とりあえず毎日バックアップだけ取りたい」
そんなケースにまさに最適です。


■ 応用アイデア

  • バックアップ対象を拡張子で絞り込む
  • サブフォルダもバックアップ対象にする
  • ネットワークドライブへ自動コピー
  • タスクスケジューラで毎日自動実行

バッチファイルなので柔軟にカスタマイズできます。


■ まとめ

このスクリプトを使えば、

  • 毎日のバックアップはワンクリック
  • 同じ内容のファイルは勝手にスキップ
  • フォルダが散らからない
  • HDD の節約にもなる

という 非常に手軽で効率的なバックアップ環境が手に入ります。

ぜひ、あなたの開発環境・作業フォルダにも導入してみて下さい!

質問や追加機能の相談があれば、気軽にコメントしてください。


追記

この記事は ChatGPT で添削しております。
また、このツールは ChatGPT で作成したツールです。
生成 AI による文章・ツールが苦手な方は申し訳ありません。


📘 関連リンク(再掲)

👉 今まで作ったサイト

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?