@ECHO OFF
SETLOCAL
SET BATDIR=%~dp0

REM ■コピー元ファイルリストの各ファイルについて、コピー先ディレクトリ内の同名ファイルと比較し、
REM │コピー先ディレクトリ内の同名ファイルが存在しないか、内容が一致しない場合のみ、コピーする。
REM │Makefile等で大きなプロジェクトをビルドする時に、同じ内容でタイムスタンプだけ新しくなると、
REM │無駄なビルドが生じることを避けるために作成したバッチファイルです。
REM │コピー元ファイルリストには、複数のファイルや、ワイルドカードも指定できます。
REM │コピー元ファイル名がドライブやパスを含んでいる場合、コピー先には、ドライブやパスを除いた、
REM │フラットな構造としてコピーします。
REM ■使い方
REM │CALL FC_COPY.bat コピー元ファイル1 コピー元ファイル2 ... コピー元ファイルN コピー先ディレクトリ
REM ■使用例
REM │CALL FC_COPY.bat C:\Folder1\File1.TXT C:\Folder2\*.BIN D:\Folder3
REM │…C:\Folder1\File1.TXTとC:\Folder2\*.BINを、D:\Folder3の直下にフラットな構造でコピーします。

REM //--------------------------------------------------------------------------
REM // * Wed Sep 10 14:24:02 JST 2014 Naoyuki Sawa
REM // - 1st リリース
REM //--------------------------------------------------------------------------
REM // * Sun Mar 29 09:52:07 JST 2015 Naoyuki Sawa
REM // - ファイルを比較するコマンドを、DOSコマンドの「FC」⇒UnxUtilsの「cmp.exe」に変更しました。
REM //   「FC」は(>NULにリダイレクトしているとは言え)相違点を全て出力するので、相違点が多い時に長時間かかっていました。
REM //   当ツールでは相違の有無のみが判断できれば充分なのに、相違箇所が全て出力されるのを待っていて無駄でした。
REM //   「cmp.exe」は'-s'オプションを指定すれば相違の有無の結果コードだけを返して相違点を出力しません。
REM //   ファイルが一致しない事を判断してコピーを開始するまでの時間が短くなりました。
REM //--------------------------------------------------------------------------

REM □変数SrcFilesに、コピー元ファイルリストとして、最後以外の引数を格納する。
REM │変数DestDir に、コピー先ディレクトリ  として、最後以外の引数を格納する。
REM │引数が2個未満である場合は、エラー終了する。
REM │引数が9個超過である場合は、本来はエラーであるが、現在の実装ではチェックしていない。
REM │尚、このように1行で書く場合は、SETの最小範囲を()で囲まなければいけない。
REM │最小範囲でなく( SET DestDir=%9 )と囲むと、余分な空白も取り込んでしまう。
            ( (SET SrcFiles=%1 %2 %3 %4 %5 %6 %7 %8) & (SET DestDir=%9) )
IF "%9"=="" ( (SET SrcFiles=%1 %2 %3 %4 %5 %6 %7)    & (SET DestDir=%8) )
IF "%8"=="" ( (SET SrcFiles=%1 %2 %3 %4 %5 %6)       & (SET DestDir=%7) )
IF "%7"=="" ( (SET SrcFiles=%1 %2 %3 %4 %5)          & (SET DestDir=%6) )
IF "%6"=="" ( (SET SrcFiles=%1 %2 %3 %4)             & (SET DestDir=%5) )
IF "%5"=="" ( (SET SrcFiles=%1 %2 %3)                & (SET DestDir=%4) )
IF "%4"=="" ( (SET SrcFiles=%1 %2)                   & (SET DestDir=%3) )
IF "%3"=="" ( (SET SrcFiles=%1)                      & (SET DestDir=%2) )
IF "%2"=="" ( EXIT /B 1 )
IF "%1"=="" ( EXIT /B 1 )

REM □コピー先フォルダが存在することを確認します。
REM │コピー先フォルダが存在しない場合は、エラー終了します。
REM │バッチでフォルダの存在確認をするときは、対象のパスの末尾に\を付加してEXISTで判定すればよい。
REM │参考URL:フリーエンジニア開発雑記「バッチファイルでフォルダの存在確認」(http://mosazo.sadist.jp/wordpress/8/)
IF NOT EXIST %DestDir%\ EXIT /B 1

REM □コピー元ファイルリストの各ファイルについて…
REM │引数で指定されたコピー元ファイル名が、ワイルドカードを含んでいる場合は、ここで展開されます。
FOR %%i IN (%SrcFiles%) DO (

  REM □コピー元ファイルが存在することを確認します。
  REM │コピー元ファイルが存在しない場合は、エラー終了します。
  IF NOT EXIST %%i EXIT /B 1

  REM □コピー元ファイルと、コピー先フォルダ内の同名ファイルを、バイナリ比較します。
  REM │コピー先フォルダ内の同名ファイル名の指定には、コピー元ファイルのドライブとパスを省くことに注意せよ。(%%~nxi)
  REM │コピー先フォルダ内の同名ファイルは、存在していても存在していなくても構わない。
  REM │存在していて不一致の場合も、存在していない場合も、ERRORLEVEL 1以上になります。
  REM │存在していない場合はFCがエラーメッセージを表示するが、当バッチ処理の観点からはエラーではないので、抑制する。
 REM //{{2015/03/29変更:ファイルを比較するコマンドを、DOSコマンドの「FC」⇒UnxUtilsの「cmp.exe」に変更しました。
 REM // FC /B %%i %DestDir%\%%~nxi >NUL 2>&1
 REM //↓2015/03/29変更:ファイルを比較するコマンドを、DOSコマンドの「FC」⇒UnxUtilsの「cmp.exe」に変更しました。
  cmp.exe -s %%i %DestDir%\%%~nxi
 REM //}}2015/03/29変更:ファイルを比較するコマンドを、DOSコマンドの「FC」⇒UnxUtilsの「cmp.exe」に変更しました。

  IF ERRORLEVEL 1 (
    REM □存在していて不一致,又は,存在していない場合は、コピーする。
    REM │COPYが成功時にメッセージを表示するが、不要なので抑制する。
    REM │COPYが失敗した場合は、エラー終了します。
    ECHO copy %%i
    COPY %%i %DestDir% >NUL 2>&1
    IF ERRORLEVEL 1 EXIT /B 1
  ) ELSE (
    REM □存在していて一致している場合は、コピーしない。
    ECHO skip %%i
  )

)
