フォルダ構造だけをコピーするバッチです。
ちょっと時機を逸しましたが、年度末に翌年度のために、今年度と同じフォルダ構造を作りたいことってないでしょうか?
「今年度のファイルはいらないのだが、フォルダ構造のみコピーしたい!」
という場合に、今まではファイル毎コピーして、ファイルを消してました。
まー、年に1回なので、あきらめてましたが、フォルダのみコピーしてみたくなったので、さくっと作りました。
もちろん、テンプレート的にファイルの無いフォルダ構造を作っておいて、それをコピーするという方法もありますが、1年運用していると、フォルダが増えたりして、テンプレートのメンテナンスが面倒なんですよね。
何度か迷宮入りしました。
仕様としては、年度は指定せずに、選んだディレクトリ名から自動検出させたかったです。
利用の状況としては、2023年の12月ころに2023年のフォルダを2024年のフォルダにコピーしたい場合もあれば、2024年3月になってから、2023年のフォルダを2024年のフォルダにコピーしたい場合もあります。
最初は、パスの年度を全て、新年度に置き替えればよいと考えてましたが、上位に年度みたいなディレクトリがあると、自動判定が誤動作して、何年を年々にコピーするのか誤動作しました。
例:コピー元:F102024\unnyou\2023
この場合、2023以下のフォルダ構造を2024にコピーしたいと思いますが、上位で2024も検出してしまうため、2024を2025にコピーしたいという認識をしてしまいます。
そのため、
コピー先:F102025\unnyou\2023
コピー先:F102024\unnyou\2024
どちらにしたいのか、わからないという事になってしまいます
また、パスの上位にコピー元年度と似た名称がある場合、上位も書き換えてしまい、思ったように動きません。
例:コピー元:F102023\unnyou\2023
みたいなのを置き替えると
F102024\unnyou\2024\kiroku
と上位フォルダまで変更してしまう。
以上より、指定したレベルのディレクトリ名だけを参照し、そのレベルだけ変更してコピーしないといけない事が分かりました。
完成品は以下の通りです。
指定したディレクトリだけを頼りに、年度検出するようにしました。
バッチのサブルーチンは、返り値が数字しかないです。
そのため、返り値が文字列のサブルーチンは、バッチ内共通の環境変数で受け渡ししてます。(ぱっと見、分かりやすくしたかったので、パラメータ渡しに見えますが、ダミーです。)
使い方
このバッチにコピーしたいフォルダをドラッグアンドドロップ(つまり、マウスでつかんでこのバッチ(または、バッチのショートカット)の上で離す。)という使い方を想定してます。
ダブルクリックすると入力プロンプトが出るので、入力すれば動きますが、ドラッグアンドドロップの方が簡単で間違えないと思います。
なお、上書きはしないようにしていますし、ファイルはコピーしないためファイル容量をほとんど消費しないので、コピーする前に確認せずにフォルダ構造をコピーします。
また、大量に、処理させたい場合は、パラメータ指定でこのバッチを起動する事も出来ると思います。
@echo off
chcp 932 >nul
setlocal enabledelayedexpansion
rem このバッチは、年度替わりに向けて、「来年度用のフォルダ構造のみ」を作るためのバッチです。
rem 想定している使い方は、このバッチに元となるフォルダ(フォルダ名に半角で年が必要)をドラッグ&ドロップする使い方です。
rem 上書きはせず、エラーにする仕様のため、確認せずにフォルダを作成します。
rem なお、昨年のフォルダ指定したら、今年のフォルダにコピーする。今年のフォルダを指定したら、来年のフォルダにコピーする。
rem というように、フォルダにある半角の年をキーに自動判定しますが、年以外の数字で年と同じ数字があると誤動作しますので注意ください。
set source_folder=%1
if "%source_folder%"=="" (
set /p source_folder=コピー元フォルダーパスを入力してください(Enterのみで使い方を表示します。):
)
if "%source_folder%"=="" (
echo.
echo 使い方「%0」
echo.
echo このバッチは、年度替わりに向けて、「来年度用のフォルダ構造のみ」を作るためのバッチです。
echo.
echo 想定している使い方は、このバッチにコピー元となるフォルダ(フォルダ名に半角で年が必要)をドラッグ&ドロップする使い方です。
echo 上書きはせず、エラーにする仕様のため、確認せずにフォルダを作成します。
echo.
echo なお、昨年のフォルダ指定したら、今年のフォルダにコピーする。今年のフォルダを指定したら、来年のフォルダにコピーする。
echo というように、フォルダにある半角の年をキーに自動判定しますが、フォルダ名に年と同じ数字があると誤動作しますので注意ください。
echo また、半角の昨年または、今年の年が無いフォルダを指定すると、エラーになります。
goto :end
)
rem コピー元フォルダの存在チェックをします。
if not exist "%source_folder%" (
echo コピー元フォルダが見つかりません。
goto :end
)
rem コピー元フォルダパスの長さを調べる。
call :count_length %source_folder%
set dir_length=%ERRORLEVEL%
if %dir_length% leq 4 (
echo フォルダに年[YYYY]がないと処理できません。
goto :end
)
rem 昨年のフォルダから今年のフォルダにコピーするパターンが一般的かと思います。
set destination_year=%date:~0,4%
set /a source_year=%destination_year%-1
rem 分かりやすく、パラメータのように記述してますが、環境変数を共用してます。
call :set_destination %dir_length% %source_folder% %source_year% %destination_year%
if %ERRORLEVEL% equ 0 ( goto exec_copy )
rem 昨年でない場合は、今年のフォルダから来年のフォルダにコピーします。
set source_year=%date:~0,4%
set /a destination_year=!source_year!+1
rem 分かりやすく、パラメータのように記述してますが、環境変数を共用してます。
call :set_destination %dir_length% %source_folder% %source_year% %destination_year%
if %ERRORLEVEL% equ 0 ( goto exec_copy )
rem 昨年、今年、いずれも見つからない場合はエラーとします。
echo フォルダに昨年または今年の年[YYYY]がないと処理できません。
goto :end
:exec_copy
rem コピー先フォルダが存在している場合は、コピーを中止します。
if exist "%destination_folder%" (
echo 既に"%destination_folder%"フォルダがすでに存在します。
echo フォルダをコピーする場合は、"%destination_folder%"フォルダを削除してから実施してください。
goto :end
)
robocopy %source_folder% %destination_folder% /e /nocopy
echo フォルダのみ、%source_folder%から、%destination_folder%にコピーしました。
:end
endlocal
pause
exit
rem ==========================================================================
rem sub routines
rem ==========================================================================
:count_length
rem 文字列の長さをカウントする。
rem INPUT
rem %1=文字列
rem OUTPUT
rem ERRORLEVEL=長さ
set count=1
set word=%1
:count_length_loop
rem %V:~m% m文字目から、最後まで
set word=%word:~1%
if "%word%"=="" exit /b %count%
set /a count+=1
goto :count_length_loop
:set_destination
rem コピー元となる年をフォルダ名から探して、コピー先フォルダ名をセットする。
rem ただし、年を探すのは、フォルダ階層の最後だけを対象にする。
rem 以下のパラメータは、グローバルの環境変数を利用してます。
rem INPUT
rem コピー元フォルダのフルパスの長さ=%dir_length%
rem コピー元フォルダのフルパス=%source_folder%
rem コピー元フォルダの年=%source_year%
rem コピー先フォルダの年=%destination_year%
rem OUTPUT
rem コピー先フォルダのフルパス=%destination_folder%
rem 指定フォルダ階層だけ検索対象とするために、まず、一番最後の¥マークを探す。
set /a yen_begin=%dir_length%-1
:set_yen_loop
rem %V:~m,n% m文字目から、n文字分
if "!source_folder:~%yen_begin%,1!"=="\" goto :set_yen_found
set /a yen_begin-=1
goto set_yen_loop
:set_yen_found
rem ¥が見つかったら、文字列の最後から、逆順に¥まで、コピー元の年を探す。
set /a year_begin=%dir_length%-4
:set_destination_loop
rem %V:~m,n% m文字目から、n文字分
if "!source_folder:~%year_begin%,4!"=="%source_year%" goto :set_destination_found
rem 最後の¥まで見つからなければ、コピー元フォルダ名に該当年は無い。
if %year_begin% equ %yen_begin% exit /b 1
set /a year_begin-=1
goto set_destination_loop
:set_destination_found
set /a after_year = %year_begin% +4
rem コピー元の年をコピー先の年に置き替える。
rem %V:~-m,n% 後ろからm文字目から、n文字分
set destination_folder=!source_folder:~0,%year_begin%!%destination_year%!source_folder:~%after_year%,%dir_length%!
exit /b 0