4種類の方法でフォルダをバックアップするバッチ

フォルダごと別のフォルダにバックアップするためのバッチです。バックアップ方法をいくつか選択できるようにしています。
※2018/08/21 全面リニューアルしました。


目次

  1. バックアップするためのバッチ
  2. 設定項目
  3. 動作
  4. ポイント解説
  5. 単純化バッチ

1. バックアップするためのバッチ

まずはバッチを挙げておきます。設定項目については後述します。

@echo off
setlocal enabledelayedexpansion
cd /d %~dp0

rem ----------【設定ここから】----------
rem 「コピー元」フォルダパスを指定してください。相対パスでも指定できます。未指定の場合、当フォルダになります。
set FolderFrom=

rem 「コピー先」フォルダパスを指定してください。相対パスでも指定できます。未指定の場合、当フォルダになります。
set FolderTo=

rem パスは「""」で囲まなくても指定できます。末尾の「\」の有無も問いません。

rem コピー元とコピー先の入れ替え設定 (0:無効、1:有効) [Default=0]
set /a Exchange=0

rem 試行ログ表示設定 (0:非表示、1:表示) [Default=1]
set /a Trial=1

rem オプション自動指定 (u:update、m:mirroring、s:synchronization、t:tree) [Default=null]
set AutoOption=
rem ----------【設定ここまで】----------

if %Exchange% equ 1 (
	set FolderTemp=%FolderFrom%
	set FolderFrom=%FolderTo%
	set FolderTo=!FolderTemp!
	echo. & echo ※注意※ 設定によりコピー元とコピー先を入れ替えました。
)

rem ----------FolderFromチェック----------
if "!FolderFrom!" == "" (
	set FolderFrom=%~dp0
	goto FolderToCheck
)

set FolderFrom=!FolderFrom:"=!
set FolderFrom=!FolderFrom:/=\!
if not "!FolderFrom:~-1!" == "\" (set FolderFrom=!FolderFrom!\)

if not "!FolderFrom:~1,1!" == ":" if not "!FolderFrom:~0,2!" == "\\" (
	set FolderFrom=%~dp0!FolderFrom!
)

if "!FolderFrom:~0,2!" == "\\" (
	set ExistTemp=!FolderFrom:~2!
	set ExistTemp=\\!ExistTemp:\\=:!
) else (
	set ExistTemp=!FolderFrom:\\=:!
)

if not exist "!ExistTemp!" (
	echo. & echo コピー元フォルダ "!FolderFrom!" は存在しません。処理を中止します。
	pause > nul & exit /b
)

rem ----------FolderToチェック----------
:FolderToCheck
if "!FolderTo!" == "" (
	set FolderTo=%~dp0
	goto SelectOp
)

set FolderTo=!FolderTo:"=!
set FolderTo=!FolderTo:/=\!
if not "!FolderTo:~-1!" == "\" (set FolderTo=!FolderTo!\)

if not "!FolderTo:~1,1!" == ":" if not "!FolderTo:~0,2!" == "\\" (
	set FolderTo=%~dp0!FolderTo!
)

if "!FolderTo:~0,2!" == "\\" (
	set ExistTemp=!FolderTo:~2!
	set ExistTemp=\\!ExistTemp:\\=:!
) else (
	set ExistTemp=!FolderTo:\\=:!
)

if exist "!ExistTemp!" (goto SelectOp)

rem コピー先フォルダが存在しない場合に新規フォルダ作成
echo. & echo コピー先フォルダ "!FolderTo!" が存在しません。
set /p AnswerA=新規に作成してよろしいですか? (y/n) : 
if /i "%AnswerA%" == "y" (goto YesA)
if /i "%AnswerA%" == "yes" (goto YesA)

echo. & echo 処理が中止されました。コピー先フォルダの設定を確認してください。
pause > nul & exit /b

:YesA
mkdir "!ExistTemp!" > nul 2>&1
if !ERRORLEVEL! neq 0 (
	echo. & echo コピー先フォルダ "!FolderTo!" を作成できません。処理を中止します。
	pause > nul & exit /b
)

rem ----------パス加工----------
:SelectOp
if /i "!FolderFrom!" == "!FolderTo!" (
	echo. & echo コピー元とコピー先に同一のフォルダが指定されています。処理を中止します。
	pause > nul & exit /b
)
echo. & echo コピー元フォルダ : !FolderFrom! & echo コピー先フォルダ : !FolderTo!

rem パス加工。ドライブは「\」あり、「"」なし。フォルダは「\」なし、空白対策に「"」あり。
set FolderFrom=!FolderFrom:~0,-1!
echo !FolderFrom! | find "\" > nul
if %ERRORLEVEL% neq 0 (
	set FolderFrom=!FolderFrom!\
) else (
	set FolderFrom="!FolderFrom!"
)

set FolderTo=!FolderTo:~0,-1!
echo !FolderTo! | find "\" > nul
if %ERRORLEVEL% neq 0 (
	set FolderTo=!FolderTo!\
) else (
	set FolderTo="!FolderTo!"
)

rem ----------オプション選択----------
if not "%AutoOption%" == "" (goto OptionBranch)

echo. & echo バックアップオプションを指定してください。
echo どのオプションでも、同一のファイルは対象外です。
echo キャンセルする場合は、オプション以外の文字を指定してください。 & echo.
echo   u : 更新 (update)
echo         新しいファイルをコピー、何も削除しない
echo   m : 完全同期 (mirroring)
echo         古いファイルも含め全てコピー、コピー元にないファイルを削除する
echo   s : 相互同期 (synchronization)
echo         相互に新しいファイルをコピー、何も削除しない
echo   t : フォルダツリー作成 (tree)
echo         フォルダのみ作成、何も削除しない & echo.

set /p AutoOption=オプション指定 (u/m/s/t) : 

:OptionBranch
if /i "%AutoOption%" == "u" (goto OpU)
if /i "%AutoOption%" == "update" (goto OpU)
if /i "%AutoOption%" == "m" (goto OpM)
if /i "%AutoOption%" == "mirroring" (goto OpM)
if /i "%AutoOption%" == "s" (goto OpS)
if /i "%AutoOption%" == "synchronization" (goto OpS)
if /i "%AutoOption%" == "t" (goto OpT)
if /i "%AutoOption%" == "tree" (goto OpT)

echo. & echo オプションが無効です。処理を中止します。
pause > nul & exit /b

rem ----------Update----------
:OpU
if %Trial% neq 1 (
	goto UYesB
)

echo. & echo 試行ログ書き出し中...
robocopy !FolderFrom! !FolderTo! /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /l /ns /ndl /log:%TEMP%\CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%\CopyTrial.log
del %TEMP%\CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto UYesB)
if /i "%AnswerB%" == "yes" (goto UYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:UYesB
robocopy !FolderFrom! !FolderTo! /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /ns /ndl /np
echo. & echo フォルダを更新しました。
pause > nul & exit /b

rem ----------Mirroring----------
:OpM
if %Trial% neq 1 (
	goto MYesB
)

echo. & echo 試行ログ書き出し中...
robocopy !FolderFrom! !FolderTo! /dcopy:t /mir /xf %0 /fft /xjd /xjf /r:0 /l /ns /ndl /log:%TEMP%\CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%\CopyTrial.log
del %TEMP%\CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto MYesB)
if /i "%AnswerB%" == "yes" (goto MYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:MYesB
robocopy !FolderFrom! !FolderTo! /dcopy:t /mir /xf %0 /fft /xjd /xjf /r:0 /ns /ndl /np
echo. & echo フォルダを完全同期しました。
pause > nul & exit /b

rem ----------Synchronization----------
:OpS
if %Trial% neq 1 (
	goto SYesB
)

echo. & echo 試行ログ書き出し中...
robocopy !FolderTo! !FolderFrom! /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /l /ns /ndl /log:%TEMP%\CopyTrial.log
(echo.& echo.) >> %TEMP%\CopyTrial.log
robocopy !FolderFrom! !FolderTo! /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /l /ns /ndl /log+:%TEMP%\CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%\CopyTrial.log
del %TEMP%\CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto SYesB)
if /i "%AnswerB%" == "yes" (goto SYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:SYesB
robocopy !FolderTo! !FolderFrom! /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /ns /ndl /np
robocopy !FolderFrom! !FolderTo! /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /ns /ndl /np
echo. & echo フォルダを相互同期しました。
pause > nul & exit /b

rem ----------Tree----------
:OpT
if %Trial% neq 1 (
	goto TYesB
)

echo. & echo 試行ログ書き出し中...
robocopy !FolderFrom! !FolderTo! /e /nocopy /xx /xjd /r:0 /l /log:%TEMP%\CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%\CopyTrial.log
del %TEMP%\CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto TYesB)
if /i "%AnswerB%" == "yes" (goto TYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:TYesB
robocopy !FolderFrom! !FolderTo! /e /nocopy /xx /xjd /r:0 /np
echo. & echo フォルダツリーを作成しました。
pause > nul & exit /b

2. 設定項目

汎用性を持たせるために、以下の設定項目を設けています。

  1. set FolderFrom= … 「コピー元」フォルダパス
    相対パスでも指定できます。未指定の場合、このバッチがあるフォルダになります。
  2. set FolderTo= … 「コピー先」フォルダパス
    相対パスでも指定できます。未指定の場合、このバッチがあるフォルダになります。
  3. set /a Exchange=0 … コピー元とコピー先の入れ替え設定 (0:無効、1:有効)
    フォルダ指定を入れ替えて試行したいときのための設定です。デフォルトでは無効です。
  4. set /a Trial=1 … 試行ログ表示設定 (0:非表示、1:表示)
    バックアップを実行する前に試行ログを表示します。表示後にキャンセルすることもできます。
    非表示にすると、試行せずにバックアップします。デフォルトでは表示します。
  5. set AutoOption= … オプション自動指定 (u: update、m: mirroring、s: synchronization、t: tree) バックアップ方法のオプションをあらかじめ指定しておくことができます。

フォルダパスは「””」で囲まなくても指定できます。末尾の「\」の有無も問いません。
コピー元とコピー先は、異なるフォルダを指定してください。


3. 動作

3-1. フォルダパスを指定して実行する

コピー元とコピー先を指定して、バッチを実行してください。
まずフォルダパスのチェックを行います。パスが未指定の場合は、このバッチがあるフォルダのパスを自動で入力します。

コピー先のフォルダが存在しない場合は、新規に作成しても良いかどうか選択肢が出ます。

3-2. バックアップオプションを指定する

フォルダパスのチェックを通過すると、バックアップオプションの選択肢が出ます。

  • u : 更新 (update)
    新しいファイルをコピー、何も削除しない
  • m : 完全同期 (mirroring)
    古いファイルも含め全てコピー、コピー元にないファイルを削除する
  • s : 相互同期 (synchronization)
    相互に新しいファイルをコピー、何も削除しない
  • t : フォルダツリー作成 (tree)
    フォルダのみ作成、何も削除しない

最も安全なオプションは「u : 更新」です。コピー元フォルダ内のサブフォルダやファイルのうち、コピー先にないか、より新しいフォルダとファイルのみをコピー先へ上書きします。コピー先にのみ存在するファイルは削除されません。

一方、「m : 完全同期」はコピー先をコピー元と全く同じ状態にします。いわゆるミラーリングで、コピー先にのみ存在するフォルダやファイルは削除されます。

「s : 相互同期」は、コピー元とコピー先それぞれにおいて、より新しいフォルダやファイルで相互に上書きします。処理としては「u : 更新」の動作を相互に行うだけですので、何も削除されません。
このオプションを選択したときの試行ログは、「コピー先 → コピー元」と「コピー元 → コピー先」の2種類が同一ログファイル内に記述されます。

「t : フォルダツリー作成」は、コピー元のフォルダ構造のみをコピー先に作成します。ファイルの上書きはありません。

3-3. 試行ログを確認してから実際の処理を開始する

試行ログを表示する設定にしていれば、自動的にログファイルが開きます。この段階では実際のバックアップ作業はまだ行われていません。
ログファイルを閉じると、バッチのウィンドウでバックアップ処理を開始するかどうか尋ねられますので、開始して良ければ「y」を入力してください。

処理が終わると完了メッセージが表示されます。


4. ポイント解説

4-1. パスのチェックと整形

set FolderFrom=!FolderFrom:"=!
set FolderFrom=!FolderFrom:/=\!
if not "!FolderFrom:~-1!" == "\" (set FolderFrom=!FolderFrom!\)

まずはパスから「”」を除去し、「/」を「\」に変換します。それから末尾の文字を取得し、それが「\」でない場合は付加する処理をしています。
これでパスの書式が統一されるので、次に相対パスへの対応をします。

if not "!FolderFrom:~1,1!" == ":" if not "!FolderFrom:~0,2!" == "\\" (
	set FolderFrom=%~dp0!FolderFrom!
)

パスの2文字目が「:」のときを絶対パス、最初の2文字が「\\」のときをサーバーパスと判断し、それ以外を相対パスとして判定しています。
「robocopy」コマンドがサーバーパスに対応しているのでこのようにしています。

if "!FolderFrom:~0,2!" == "\\" (
	set ExistTemp=!FolderFrom:~2!
	set ExistTemp=\\!ExistTemp:\\=:!
) else (
	set ExistTemp=!FolderFrom:\\=:!
)

if not exist "!ExistTemp!" (
	echo. & echo コピー元フォルダ "!FolderFrom!" は存在しません。処理を中止します。
	pause > nul & exit /b
)

「exist」を使ってフォルダの存在判定をします。直前で「\」を「:」に変換してから判定しているのは、「exist」が「\」の数に厳密でないからです。
例えばパスの末尾で「\\」と2つ重なっていてもフォルダが存在すると判定されますが、後の「robocopy」ではエラーになってしまいます。

4-2. パスの加工

set FolderFrom=!FolderFrom:~0,-1!
echo !FolderFrom! | find "\" > nul
if %ERRORLEVEL% neq 0 (
	set FolderFrom=!FolderFrom!\
) else (
	set FolderFrom="!FolderFrom!"
)

「robocopy」のパス指定は少し特殊なため、パスを加工します。様々なパターンでテストした結果、以下のルール通りにすればうまく動作します。

  • ドライブ … 「”」で囲まない。最後に「\」を付ける。
    例 : C:\
  • フォルダ … パスに空白を含む場合は「”」で囲む。その際に末尾の「\」は付けない。
    例 : “D:\Test Folder”
    あるいはパスに空白がなければ「”」で囲まなくてもよい。その際は末尾に「\」があってもよい。
    例 : E:\TestFolder\

このルールにしたがい、ドライブは「\」を付加し、それ以外は「”」で囲んで末尾の「\」を付けないようにしています。

4-3. robocopyのオプション

バックアップ処理にはすべて「robocopy」コマンドを使っています。コマンドオプションの組み合わせを変えて、バックアップ方法のバリエーションを作っているだけです。

使用したコマンドオプションを主として表にしました。

種類オプション説明
コピーオプション/sサブディレクトリをコピーするが、空のディレクトリはコピーしない。
/e空のディレクトリを含むサブディレクトリをコピーする。
/dcopy:tディレクトリタイムスタンプをコピーする。
/nocopyファイル情報をコピーしない。
/purge既にコピー元に存在しないコピー先のファイル/ディレクトリを削除する。
/mirディレクトリツリーをミラー化する (/eおよび/purgeと同等)。
/moveファイルとディレクトリを移動する。
ファイル選択オプション/xf ファイル指定された名前/パス/ワイルドカードに一致するファイルを除外する。
/xd ディレクトリ指定された名前/パスに一致するディレクトリを除外する。
/xo古いファイルを除外する。
/xxコピー先にだけ存在するファイルとディレクトリを除外する。
/fft2秒の粒度を仮定する (2秒以内を同一ファイルとして扱う)。
/xjdディレクトリの接合ポイントを除外する。
/xjfファイルの接合ポイントを除外する。
再試行オプション/R:n失敗したコピーに対する再試行数:既定値は1,000,000。
ログオプション/lいずれのファイルにも、コピー、タイムスタンプの追加、または削除を実施しない。
/nsファイルサイズをログに記録しない。
/ncファイルクラスをログに記録しない。
/ndlディレクトリ名をログに記録しない。
/npコピーの完了率を表示しない。
/log:ファイルログファイルに状態を出力する (既存のログを上書き)。
/log+:ファイルログファイルに状態を出力する (既存のログファイルに追加)。

5. 単純化バッチ

特定の目的に応じた単純化バッチも書いておきます。試行ログは出力される設定です。
パスのチェックを行いませんので、4-2. で書いたルールにしたがって正確に記述してください。

5-1. 更新

@echo off
cd /d %~dp0

rem 「コピー元」フォルダパスを指定してください。
set FolderFrom=

rem 「コピー先」フォルダパスを指定してください。
set FolderTo=

echo. & echo 試行ログ書き出し中...
robocopy %FolderFrom% %FolderTo% /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /l /ns /ndl /log:%TEMP%CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%CopyTrial.log
del %TEMP%CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto UYesB)
if /i "%AnswerB%" == "yes" (goto UYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:UYesB
robocopy %FolderFrom% %FolderTo% /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /ns /ndl /np
echo. & echo フォルダを更新しました。
pause > nul & exit /b

5-2. 完全同期

@echo off
cd /d %~dp0

rem 「コピー元」フォルダパスを指定してください。
set FolderFrom=

rem 「コピー先」フォルダパスを指定してください。
set FolderTo=

echo. & echo 試行ログ書き出し中...
robocopy %FolderFrom% %FolderTo% /dcopy:t /mir /xf %0 /fft /xjd /xjf /r:0 /l /ns /ndl /log:%TEMP%CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%CopyTrial.log
del %TEMP%CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto MYesB)
if /i "%AnswerB%" == "yes" (goto MYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:MYesB
robocopy %FolderFrom% %FolderTo% /dcopy:t /mir /xf %0 /fft /xjd /xjf /r:0 /ns /ndl /np
echo. & echo フォルダを完全同期しました。
pause > nul & exit /b

5-3. 相互同期

@echo off
cd /d %~dp0

rem 「コピー元」フォルダパスを指定してください。
set FolderFrom=

rem 「コピー先」フォルダパスを指定してください。
set FolderTo=

echo. & echo 試行ログ書き出し中...
robocopy %FolderTo% %FolderFrom% /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /l /ns /ndl /log:%TEMP%CopyTrial.log
(echo.& echo.) >> %TEMP%CopyTrial.log
robocopy %FolderFrom% %FolderTo% /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /l /ns /ndl /log+:%TEMP%CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%CopyTrial.log
del %TEMP%CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto SYesB)
if /i "%AnswerB%" == "yes" (goto SYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:SYesB
robocopy %FolderTo% %FolderFrom% /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /ns /ndl /np
robocopy %FolderFrom% %FolderTo% /e /dcopy:t /xf %0 /xo /xx /fft /xjd /xjf /r:0 /ns /ndl /np
echo. & echo フォルダを相互同期しました。
pause > nul & exit /b

5-4. フォルダツリー作成

@echo off
cd /d %~dp0

rem 「コピー元」フォルダパスを指定してください。
set FolderFrom=

rem 「コピー先」フォルダパスを指定してください。
set FolderTo=

echo. & echo 試行ログ書き出し中...
robocopy %FolderFrom% %FolderTo% /e /nocopy /xx /xjd /r:0 /l /log:%TEMP%CopyTrial.log
echo. & echo ログファイルを閉じて処理を続行してください。 & echo.
%TEMP%CopyTrial.log
del %TEMP%CopyTrial.log

set /p AnswerB=処理を開始しますか? (y/n) : 
if /i "%AnswerB%" == "y" (goto TYesB)
if /i "%AnswerB%" == "yes" (goto TYesB)

echo. & echo 処理が中止されました。
pause > nul & exit /b

:TYesB
robocopy %FolderFrom% %FolderTo% /e /nocopy /xx /xjd /r:0 /np
echo. & echo フォルダツリーを作成しました。
pause > nul & exit /b

Leave a comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

20 − twenty =