6

I need to write a script for binary comparison of all files within 2 folders recursively. The 2 folders are installation folders and contain same files, but they are installation folders of different versions. I need to find which files (.dll, .lib, .exe) have changed with regard to previous versions.

I have tried using fc command

fc /b %1\* %2\* > result.txt 

But, it compares files only inside the stated folder. I need to recursively compare all files within all folders.

I thought this can be achieved by for loop.

For /r C:\test\%%f in (*) do @fc /b %%f C:\test\%2\%%~nxf > result.txt  

The problem here is %%~nxf which only gives the file name not the relative path.

I tried using forfiles command:

forfiles /s /p C:\test\%1 /m * /c "cmd /c @fc /b %1\@relpath %2\@relpath"

@relpath introduces .\ in the middle of the path, which is messing up my complete path. Any pointers on this one will be highly appreciated.

Please help!

Andriy M
  • 76,112
  • 17
  • 94
  • 154
Kumar Vikramjeet
  • 253
  • 1
  • 4
  • 13

3 Answers3

8

This is solution requires to use 3rd-party tool, but it is very efficient.

You will need to get md5deep - it is just 20KB executable.

Then, execute it against first directory like this:

md5deep -l -r dir1 > old.txt

Result is saved in old.txt and looks like this:

e7c3fcf5ad7583012379ec49e9a47b28  .\a\file1.bin
2ef76c2ecaefba21b395c6b0c6af7314  .\b\file2.bin
45e19bb4b38d529d6310946966f4df12  .\c\file3.bin
...

Then, run it in negative matching mode against second directory:

md5deep -l -r -X old.txt dir2

It will print checksum and names of all files in second directory which differ from original.

You can also run it in standard checksumming mode against second dir and compare the result yourself.

At any rate, I doubt that you can get away with just cmd: you will have to write something in more higher-level language, like C/C++/C#/whatever.

mvp
  • 111,019
  • 13
  • 122
  • 148
  • Thanks for help. I guess the task is very small and this script will be used again and again. I think this task can be achieved by few lines of script only of cmd. Using a extra piece of software doesn't seem like a wise choice. – Kumar Vikramjeet Feb 04 '13 at 09:16
  • I personally think that you are underestimating complexity of this, and how much effort md5deep can save for you, especially considering future maintenance, should list of files ever change. But of course, this is up to you. – mvp Feb 04 '13 at 09:20
  • 1
    md5deep was a perfect solution for my problem. Thanks mvp! – JohnLaird Nov 23 '16 at 15:10
  • 1
    The presumably new name and command `hashdeep` needs slightly different options: `-k old.txt -X -l -r`. Ordering seems to matter. It handled a few 100,000 files pretty well. – Andreas Feb 21 '23 at 02:12
3

My final code :-

@echo off
set count=0
del /f result.txt
subst Y: %1
subst Z: %2
for /r Y: %%f in (*) do (fc /b "%%f" "Z:%%~pnxf" |  find "no diff" >nul
if ERRORLEVEL 1 echo "%1%%~pnxf is different" >> result.txt
set /a count+=1)

subst Y: /D
subst Z: /D


echo Total Files Compared = %count% 

One thing, I didn't get, this script is not checking all differences. Once a difference is found, it gets printed on the result page. This was the exact thing I wanted. I guess the find command takes line by line as input, and once the string is not found, it quits, though I'm not sure. It's a very common problem, still I wasn't able to find the solution on the net, that's why I'm posting it here.

Kumar Vikramjeet
  • 253
  • 1
  • 4
  • 13
2

A workaround could be to use subst to associate the path with a drive letter, and compare both. For example:

subst Y: "C:\test 1"
subst Z: "C:\test 2"
for /r Y: %%f in (*) do fc /b "%%f" "Z:%%~pnxf"
subst Y: /d
subst Z: /d

Hope this helps

EDIT: Handle the fc command output (long):

setlocal enabledelayedexpansion
subst Y: /d
subst Z: /d
pause
subst Y: "C:\test 1"
subst Z: "C:\test 2"
for /r Y: %%f in (*) do (
  set diff=1&for /f "tokens=1,2,3,4 delims= " %%i in ('fc /b "%%f" "Z:%%~pnxf"') do (
    if "%%i"=="Comparing" (echo.) else (
      if "%%k"=="longer" (echo LONGER   : %%j) else (
        if "%%i"=="FC:" echo NO DIFF  : %%f
        if "%%l"=="" (if "!diff!"=="1" (
          echo DIFFERENT: %%f
          echo %%i %%j %%k
          set diff=2
        ))
      )
    )
  )
)
subst Y: /d
subst Z: /d
user2033427
  • 853
  • 7
  • 8
  • Nice solution, but folder/file name with spaces are not getting handled here. Thanks. – Kumar Vikramjeet Feb 04 '13 at 11:14
  • @vik001ind: Have you tried adding double quotes around the names in the `FC` call? – Andriy M Feb 04 '13 at 17:36
  • Great! it works smoothly. Thanks Andriy and user2033427. I have added 2 more lines for removing the virtual drives i.e. subst Y: /D .Is it possible to quiet the fc command once it gets one difference? it will save me a huge amount of time. I tried> for /r Y: %%f in (*) do fc /lb1 /b "%%f" "Z:%%~pnxf" , but this still checks all differences. I'm also thinking of customizing the error message using errorlevel, I want to print just the not matching filename. – Kumar Vikramjeet Feb 05 '13 at 04:22
  • Added the subst y: /d part. I'll look at this maybe tomorrow when I have more time, might need something more complicated.. – user2033427 Feb 05 '13 at 06:36
  • @vik001ind Handled the fc command output and quieted it once it gets one difference. – user2033427 Feb 08 '13 at 10:21