Windows上でのフォルダのミラーリング修正版

新マシンになる前にWindowsでのHDDミラーリングのためのバッチファイルを作成しましたが、

メモ: Windows上でのフォルダのミラーリング

USB3.0のHDDを常時接続しなくなったのと、やっぱり1台だけミラーリングできるようなものもあったほうがいいんじゃないかとか思い始めたのでスクリプトを修正します。

変更点は

  • はい、いいえではなく同期するドライブを指定する
  • デスクトップのパスはユーザディレクトリ\Desktopではなくなったことへの対応

の2点です。

で、対応版が下記の内容です。

@echo off
set /p result="input sync target(v/w/x)  : %result%"

FOR /F "TOKENS=1,2,*" %%I IN ('REG QUERY "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "Desktop"') DO IF "%%I"=="Desktop" SET DESKTOP_PATH=%%K

set time2=%time: =0%
ECHO %result% | find "v" >NUL
IF NOT ERRORLEVEL 1 (
 robocopy "V:\main" "V:\mirror"  /MIR /R:0 /W:0 /V /DCOPY:T /LOG:"%DESKTOP_PATH%\v_%date:~-10,4%%date:~-5,2%%date:~-2,2%_%time2:~0,2%%time2:~3,2%.log" /TEE /XJD /XJF /NP /XD "$RECYCLE.BIN"
)

set time2=%time: =0%
ECHO %result% | find "w" >NUL
IF NOT ERRORLEVEL 1 (
 robocopy "W:\main" "W:\mirror"  /MIR /R:0 /W:0 /V /DCOPY:T /LOG:"%DESKTOP_PATH%\w_%date:~-10,4%%date:~-5,2%%date:~-2,2%_%time2:~0,2%%time2:~3,2%.log" /TEE /XJD /XJF /NP /XD "$RECYCLE.BIN"
)

set time2=%time: =0%
ECHO %result% | find "x" >NUL
IF NOT ERRORLEVEL 1 (
 robocopy "X:\main" "X:\mirror"  /MIR /R:0 /W:0 /V /DCOPY:T /LOG:"%DESKTOP_PATH%\x_%date:~-10,4%%date:~-5,2%%date:~-2,2%_%time2:~0,2%%time2:~3,2%.log" /TEE /XJD /XJF /NP /XD "$RECYCLE.BIN"
)

最初のインタラクティブなところは(y/n)ではなく(v/w/x)にしてあります。
指定したドライブレターで同期対象を選択するようにしています。
複数ドライブの時はそのドライブレターをすべて入力します。
vxと入力するとvドライブとxドライブ両方共同期する的な。

そして個別の処理のところにifで分岐してます。

ECHO %result% | find "v" >NUL
IF NOT ERRORLEVEL 1 (
 (略)
)

この条件文は入力内容にvが見つかれば、という意味なのでvが入力されていればvを同期しますというヤツです。

そしてこのif文周辺で不思議なところが

set time2=%time: =0%
ECHO %result% | find "v" >NUL
IF NOT ERRORLEVEL 1 (

ココです。
if文の条件に一致しない場合は不要になるtime2への代入なのになぜifのスコープの外にいるのか。

それは↓の理由によるものです。

FOR文やIF文で変数の中身が消える? (DOSの変数の代入) - バッチもん研究所 blog

簡単に言うと()の中で変数に代入をしても代入されないことがある。

というものです。
必ず代入されないわけではなく代入されないというか次の処理をするまでに代入が終わってないというなんだかよくわからない遅延によるものです。

変数へ代入する処理が遅延?
非同期なの???

というなんだかよくわからない状況ですが、そんなところを根本的に解決するのは面倒なので放置、一番手っ取り早いifのスコープの外側で代入してしまえばいいだろという対応です。

なお、カッコの中に代入式を書いてしまうとログファイル名がこんな感じになってしまいました。

v_20131130_time2:~0,2time2:~3,2.log

time2 という変数に値が代入されてないからですね。
そのまま文字列として出てしまってます。

さて、代入はこれでいいとして次はディレクトリパスの取得です。

%USERPROFILE%\Desktop

これですが、これってユーザディレクトリの Desktop というディレクトリという意味なのでVドライブにデスクトップを移動させてしまっている今では使えないパスです。
じゃあ、変更したディレクトリパスはどこに保存されているかというとレジストリです。

.netとかだと簡単に取得できるんですが所詮コマンドプロンプト。
ちょっと便利そうなものとかは全然使えません。

レジストリを直接読み取るしかない。
読み取る方法というか変数に入れるには下記の方法です。

FOR /F "TOKENS=1,2,*" %%I IN ('REG QUERY "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "Desktop"') DO IF "%%I"=="Desktop" SET DESKTOP_PATH=%%K

REG QUERY でレジストリから読み取ってきてそれをいい感じに分割してデスクトップのパスに関するものだけを最後にDESKTOP_PATHに代入するという内容です。
最初に%%Iを指定しているのに最後に%%Kから値をとっているのはIを指定するとアルファベットの順で分割したものを入れていってくれるらしいです。

コレでデスクトップのパスが取得できるので後はif文の中でフォルダパスとして使っています。

で、実行してみましたが、無事完了しました。

コメント