How to Compare Two Folders in Windows Using Command Line

Comparing folders is a common task for many Windows users, especially when managing files, backing up data, or ensuring consistency across directories. While graphical tools exist, sometimes a command-line approach offers speed and automation. This article will guide you through using a batch script, ccomp.cmd, to effectively Windows Compare Two Folders.

Understanding the ccomp.cmd Script

The ccomp.cmd script is a command-line tool designed to compare two directory trees. It analyzes the file and folder paths within the specified directories and identifies differences. This script is particularly useful for users who need a quick and scriptable way to find discrepancies between two folders without relying on visual comparison or third-party software with graphical interfaces.

Key Features

  • Path-based comparison: The script primarily focuses on comparing the paths of files and folders.
  • Size difference detection: For files present in both directories, the script can compare file sizes and report if there are differences.
  • Command-line utility: Being a command-line tool, it’s ideal for automation and use in scripts or batch files.
  • Output to console: The comparison results are displayed directly in the command console, making it easy to review the findings.

How to Use ccomp.cmd to Compare Folders

To utilize ccomp.cmd, you first need to create the script file. Open a text editor like Notepad, copy the code provided below, and save the file as ccomp.cmd. Ensure the “Save as type” is set to “All Files” to prevent it from being saved as a .txt file.

@echo off
if "!ERRORLEVEL!" == "%ERRORLEVEL%" (
    REM if delayed expansion is enabled:
    (
        echo.
        echo ERROR: This script must be called in a Disabled Delayed Expansion block ^(default^)^^^!
        echo.
        call :PressAKey "Press a key to exit..."
        echo.
    )>con
    exit /b 1
)
setlocal disabledelayedexpansion
if defined _first_time goto :label1MAIN

REM Test CHCP:
chcp /?>nul 2>nul||(
    (
        echo.
        & echo ERROR: Could not start chcp ^(necessary^)!
    )>con
    exit /b 1
)

REM Get the initial code page:
call :GetCurrentCodePage _initial_CP

REM Change the code page (character encoding) for "CON" (console) to 65001 (UTF-8):
set _con_error=false
mode con cp select=65001>nul 2>nul||(
    (
        echo.
        & echo WARNING: Could not change the code page for CON ^(Console^)!
    )>con
    set _con_error=true
)

set _help_flag=0
set /a _count=1
set "_script_path=%~Dpnx0"

:repeat1MAIN
if _%1_ == _""_ (
    REM "%1" is """"
    set _param%_count%=""
    shift
    set /a _count+=1
    goto :repeat1MAIN
) else (
    if /i "%~1" == "/?" (
        set _help_flag=1
        shift
        goto :repeat1MAIN
    ) else (
        if /i "%~1" == "/help" (
            set _help_flag=1
            shift
            goto :repeat1MAIN
        ) else (
            if /i "%~1" == "/h" (
                set _help_flag=1
                shift
                goto :repeat1MAIN
            ) else (
                if not "%~1" == "" (
                    REM if "%1" is null, it means that no more parameters are provided
                    set "_param%_count%=%~1"
                    shift
                    set /a _count+=1
                    goto :repeat1MAIN
                )
            )
        )
    )
)
set /a _count-=1
set /a _param_count=_count

REM start Checking parameters /
if "%_help_flag%" == "1" (
    call :DisplayHelp
    exit /b 0
) else (
    if %_param_count% gtr 2 (
        (
            echo.
            & echo ERROR: Too many parameters!
        )>con
        exit /b 1
    ) else (
        if %_param_count% lss 2 (
            (
                echo.
                & echo ERROR: Too few parameters!
            )>con
            exit /b 1
        )
    )
)

set "_error=false"

if "%_param1%" == """" (
    (
        echo.
        & echo ERROR: First provided directory parameter must not be empty!
    )>con
    set "_error=true"
) else (
    call :TestIfDirAcccessible _param1 _is_param1_dir
    setlocal enabledelayedexpansion
    if not "!_is_param1_dir!" == "0" (
        endlocal
        (
            echo.
            & echo ERROR: First provided directory parameter: "%_param1%" is not a directory or is not accessible!
        )>con
        set "_error=true"
    ) else (
        endlocal
    )
)

if "%_param2%" == """" (
    (
        echo.
        & echo ERROR: Second provided directory parameter must not be empty!
    )>con
    set "_error=true"
) else (
    call :TestIfDirAcccessible _param2 _is_param2_dir
    setlocal enabledelayedexpansion
    if not "!_is_param2_dir!" == "0" (
        endlocal
        (
            echo.
            & echo ERROR: Second provided directory parameter "%_param2%" is not a directory or is not accessible!
        )>con
        set "_error=true"
    ) else (
        endlocal
    )
)

call :TestIfPathIsUNC _param1 _result1
call :TestIfPathIsUNC _param2 _result2

if "%_result1%" == "true" (
    set "_error=true"
    (
        echo.
        & echo ERROR: Path1: "%_param1%" seems to be a UNC path ^(contains \^), and UNC paths are not supported by this program ^(but a UNC path can be mounted ^(for example by using pushd^), in order to make it accessible^)!
    )>con
)

if "%_result2%" == "true" (
    set "_error=true"
    (
        echo.
        & echo ERROR: Path2: "%_param2%" seems to be a UNC path ^(contains \^), and UNC paths are not supported by this program ^(but a UNC path can be mounted ^(for example by using pushd^), in order to make it accessible^)!
    )>con
)

if "%_error%" == "true" (
    (
        echo.
        & call :PressAKey "Press a key to exit!"
        echo.
    )>con
    exit /b 1
)

cmd /u /c ^(echo.^&echo Path1: "%_param1%"^)
cmd /u /c ^(echo.^&echo Path2: "%_param2%"^)

REM end Checking parameters /

REM If everything seems ok, proceed to PROCESSING:
pushd "%_param1%">nul
set "_param1=%CD%"
if "%_param1:~-1%" == "" set "_param1=%_param1:~0,-1%"
popd>nul

pushd "%_param2%">nul
set "_param2=%CD%"
if "%_param2:~-1%" == "" set "_param2=%_param2:~0,-1%"
popd>nul

call :ConvertDriveLetterToUpperCase _param1 _param1
call :ConvertDriveLetterToUpperCase _param2 _param2

call :GetStrLen _param1 _param1_len
call :GetStrLen _param2 _param2_len

pushd "%_script_path%..">nul
if not defined _first_time (
    call :EscapePathString _script_path _script_path_escaped
    call :EscapePathString _param1 _param1_escaped
    call :EscapePathString _param2 _param2_escaped
)
popd>nul

REM Change the code page (character encoding) for "CON" (console) to 437 (ANSI):
if "%_con_error%" == "false" (
    mode con cp select=437>nul 2>nul
)

:label1MAIN
REM CHCP 437 = ANSI CODE PAGE
REM CHCP 65001 = UTF-8 CODE PAGE

if not defined _first_time (
    set _first_time=defined
    chcp 65001>nul
    cmd /u /c ^(echo.^&echo Start time: %date% %time%^&echo.^)
    cmd /u /c ^(for /f ^"tokens=^*^" %%l in ^(^'^^^(
        setlocal^^^&^^^"%%_script_path_escaped%%^^^" ^^^"%%_param1_escaped%%^^^" ^^^"%%_param2_escaped%%^^^"^^^&title Sorting Results ^^^^^^^^^^^^^^^(finally^^^^^^^^^^^^^^^)^^^&endlocal ^^^)^^^|sort^'^) do @^(if not defined _once ^(
            set "_once=defined"^&echo %%l^) else echo %%l ^)^)^&if defined _once echo.
    set "_first_time="
    set "_second_time="
    set "_third_time="
    cmd /u /c ^(call echo End time: %%date%% %%time%%^)
    chcp 437>nul

    REM Restore the initial code page:
    chcp %_initial_CP%>nul 2>nul
) else (
    if not defined _second_time (
        set _second_time=defined
        (
            call :ProcedureAnalyzeFiles
        )
    ) else (
        if not defined _third_time (
            set "_third_time=defined"
            (
                call :ProcedureProcessFilenamesLengthAndSize1
                chcp 65001>nul
                call :ProcedureProcessFilenamesLengthAndSize2
                chcp 437>nul
                @REM After sorting: "-" is displayed before all other characters:
                @call echo ----------------------------------------""%%_count1%%""
                @title Sorting results. Please wait...
            )
        )
    )
)

endlocal & (
    if defined _first_time set "_first_time=%_first_time%"
    if defined _second_time set "_second_time=%_second_time%"
    if defined _third_time set "_third_time=%_third_time%"
)
goto :eof

REM \/// Next subroutines use jeb's syntax for working with delayed expansion: \///
:GetStrLen
REM - by jeb - adaptation
(
    setlocal EnableDelayedExpansion
    set "s=!%~1!#"
    set "len=0"
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        if "!s:~%%P,1!" NEQ "" (
            set /a "len+=%%P"
            set "s=!s:~%%P!"
        )
    )
)
(
    endlocal
    set "%~2=%len%"
    exit /b
)

:EscapePathString
(
    setlocal EnableDelayedExpansion
    set "string=!%~1!"
    call :GetStrLen string string_len
    set /a string_len-=1
    for /l %%i in (0,1,!string_len!) do (
        rem escape "^", "(", ")", "!", "&"
        if "!string:~%%i,1!" == "^" (
            set "result=!result!^^^^"
        ) else (
            if "!string:~%%i,1!" == "(" (
                set "result=!result!^^^("
            ) else (
                if "!string:~%%i,1!" == ")" (
                    set "result=!result!^^^)"
                ) else (
                    if "!string:~%%i,1!" == "^!" (
                        set "result=!result!^^^!"
                    ) else (
                        if "!string:~%%i,1!" == "&" (
                            set "result=!result!^^^&"
                        ) else (
                             if "!string:~%%i,1!" == "%%" (
                                set "result=!result!%%"
                             ) else (
                                set "result=!result!!string:~%%i,1!"
                             )
                        )
                    )
                )
            )
        )
    )
)
(
    endlocal
    set "%~2=%result%"
    exit /b
)

:TestIfDirAcccessible
(
    setlocal EnableDelayedExpansion
    set _returned_code=0
    (pushd "!%~1!">nul 2>nul||set "_returned_code=1")&&popd>nul
)
(
    endlocal
    set "%~2=%_returned_code%"
    exit /b
)

:TestIfPathIsUNC
(
    setlocal EnableDelayedExpansion
    set "_current_path=!%~1!"
    set "_is_unc_path=true"
    if "!_current_path:\=!" == "!_current_path!" (
        set "_is_unc_path=false"
    )
)
(
    endlocal
    set "%~2=%_is_unc_path%"
    exit /b
)

:GetCurrentCodePage
(
    setlocal EnableDelayedExpansion
    set "_current_cp=-1"
    for /f "tokens=1,2* delims=:" %%a in ('chcp 2^>nul') do (
        set "_current_cp=%%~b"
    )
)
(
    endlocal
    set "%~1=%_current_cp%"
    exit /b
)

:ConvertDriveLetterToUpperCase
(
    setlocal EnableDelayedExpansion
    set "_path=!%~1!"
    for /f "tokens=1 delims=" %%f in ('echo "!_path!"') do set "_path_drive=%%~df"
    set "_upper_drive=!_path_drive!"
    for %%D in (A: B: C: D: E: F: G: H: I: J: K: L: M: N: O: P: Q: R: S: T: U: V: W: X: Y: Z:) do (
        if /i "!_path_drive!" == "%%D" (
            set "_upper_drive=%%D"
            goto :endConvertDriveLetterToUpperCase
        )
    )
)
:endConvertDriveLetterToUpperCase
(
    endlocal
    set "%~1=%_upper_drive%%_path:~2%"
    exit /b
)

REM ///\ The subroutines above use jeb's syntax for working with delayed expansion: ///\

:GenerateShortName
@set "%~1=%~s2"
@goto :eof

:GenerateShortNameSize
@set "%~1=%~z2"
@goto :eof


:ProcedureAnalyzeFiles
setlocal
for /f "tokens=1,2,3,4,5* delims=/" %%p in ('chcp 65001^>nul^&^(setlocal^&^"%_script_path_escaped%^" ^"%_param1_escaped%^" ^"%_param2_escaped%^"^|sort^&endlocal^)^&chcp 437^>nul') do (
    if not defined _second_time_for1 (
        set /a _total_count=%%~p>nul 2>nul
        set /a _currrent_count=1
        set _second_time_for1=defined
    ) else (
        set /a _current_count+=1
        REM START PROCESSING:
        setlocal enabledelayedexpansion
        title Analyzing file !_current_count! of !_total_count!...
        set "_previous_file=!_current_file!"
        set "_previous_file_type=!_current_file_type!"
        set "_previous_file_visibility=!_current_file_visibility!"
        set "_previous_file_dir=!_current_file_dir!"
        REM Due to a bug in sort, an extra " is added at the end of the line, so we need to remove it:
        set "_previous_file_size=!_current_file_size:"=!"
        set "_previous_file_base_dir=!_current_file_base_dir!"
        setlocal disabledelayedexpansion
        set "_current_file=%%~p"
        set "_current_file_type=%%~q"
        set "_current_file_visibility=%%~r"
        set "_current_file_dir=%%~s"
        set "_current_file_size=%%~t"
        setlocal enabledelayedexpansion

        if "!_current_file_dir!" == "1" (
            endlocal
            set "_current_file_base_dir=%_param1%"
        ) else (
            if "!_current_file_dir!" == "2" (
                endlocal
                set "_current_file_base_dir=%_param2%"
            ) else (
                endlocal
            )
        )

        setlocal enabledelayedexpansion
        REM Due to a bug in sort, an extra " is added at the end of the line, so we need to remove it:
        set "_current_file_size=!_current_file_size:"=!"

        REM if not first time:
        if NOT "!_previous_file_type!" == "" (
            if "!_next!" == "1" (
                if "!_current_file_type!" == "!_previous_file_type!" (
                    if "!_current_file_type!" == "file" (
                        if NOT "!_current_file!" == "!_previous_file!" (
                            echo Only in "!_previous_file_dir!" - !_previous_file_type!: "!_previous_file_base_dir!!_previous_file!"
                        ) else (
                            set "_for_one_cannot_get_size=0"
                            if "!_previous_file_size!" == "-1" set "_for_one_cannot_get_size=1"
                            if "!_current_file_size!" == "-1" set "_for_one_cannot_get_size=1"
                            if "!_for_one_cannot_get_size!" == "0" (
                                if "!_previous_file_size!" GTR "!_current_file_size!" (
                                    echo "!_previous_file_base_dir!!_previous_file!" ^(!_previous_file_dir!^) size ^(!_previous_file_size!B^) is bigger than "!_current_file_base_dir!!_current_file!" ^(!_current_file_dir!^) size ^(!_current_file_size!B^)
                                ) else (
                                    if "!_previous_file_size!" LSS "!_current_file_size!" (
                                        echo "!_previous_file_base_dir!!_previous_file!" ^(!_previous_file_dir!^) size ^(!_previous_file_size!B^) is smaller than "!_current_file_base_dir!!_current_file!" ^(!_current_file_dir!^) size ^(!_current_file_size!B^)
                                    )
                                )
                            )
                        )
                    ) else (
                        if NOT "!_current_file!" == "!_previous_file!" (
                            echo Only in "!_previous_file_dir!" - !_previous_file_type!: "!_previous_file_base_dir!!_previous_file!"
                        )
                    )
                ) else (
                    echo Only in "!_previous_file_dir!" - !_previous_file_type!: "!_previous_file_base_dir!!_previous_file!"
                )
            )
        )
        endlocal
        endlocal
        endlocal
        setlocal enabledelayedexpansion
        if "%%~s" == "1" (
            endlocal
            set "_current_file_base_dir=%_param1%"
        ) else (
            if "%%~s" == "2" (
                endlocal
                set "_current_file_base_dir=%_param2%"
            ) else (
                endlocal
            )
        )
        set "_temp=%%~p"
        setlocal enabledelayedexpansion
        REM if not first time:
        if NOT "!_current_file_type!" == "" (
            if "!_next!" == "1" (
                if "%%~q" == "!_current_file_type!" (
                    if "!_temp!" == "!_current_file!" (
                        endlocal
                        set _next=2
                    ) else (
                        endlocal
                        set _next=1
                    )
                ) else (
                    endlocal
                    set _next=1
                )
            ) else (
                endlocal
                set _next=1
            )
        ) else (
            endlocal
            set _next=1
        )
        set "_current_file=%%~p"
        set "_current_file_type=%%~q"
        set "_current_file_visibility=%%~r"
        set "_current_file_dir=%%~s"
        set "_current_file_size=%%~t"
    )
)

REM Treat the last file separately:
chcp 65001>nul
setlocal enabledelayedexpansion
if "!_next!" == "1" (
    echo Only in "!_current_file_dir!" - !_current_file_type!: "!_current_file_base_dir!!_current_file!"
)
endlocal
chcp 437>nul
endlocal
goto :eof


:ProcedureProcessFilenamesLengthAndSize1
@setlocal
@set /a _count1=0
@REM Process directories:
@chcp 65001>nul
@title Loading directory paths for directory 1. Please wait...
@pushd "%_param1%">nul
@for /r /d %%f in (*) do @(
    @set "_current_path=%%~f"
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @set /a _count1+=1 >nul
    @setlocal enabledelayedexpansion
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param1_len%!///dir///1///1///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param1_len%!///dir///1///1///!_size!"
        ) else (
            @echo "!_current_path:~%_param1_len%!///dir///1///1///-1"
        )
    )
    @endlocal
)
@popd>nul
@title Please wait...

@REM Process directories:
@title Loading directory paths for directory 2. Please wait...
@pushd "%_param2%">nul
@for /r /d %%f in (*) do @(
    @set "_current_path=%%~f"
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @set /a _count1+=1 >nul
    @setlocal enabledelayedexpansion
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param2_len%!///dir///1///2///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param2_len%!///dir///1///2///!_size!"
        ) else (
            @echo "!_current_path:~%_param2_len%!///dir///1///2///-1"
        )
    )
    @endlocal
)
@popd>nul
@title Please wait...

@REM Process files:
@title Loading file paths for directory 1. Please wait...
@pushd "%_param1%">nul
@for /r %%f in (*) do @(
    @set "_current_path=%%~f"
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @set /a _count1+=1 >nul
    @setlocal enabledelayedexpansion
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param1_len%!///file///1///1///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param1_len%!///file///1///1///!_size!"
        ) else (
            @echo "!_current_path:~%_param1_len%!///file///1///1///-1"
        )
    )
    @endlocal
)
@popd>nul
@title Please wait...

@REM Process files:
@title Loading file paths for directory 2. Please wait...
@pushd "%_param2%">nul
@for /r %%f in (*) do @(
    @set "_current_path=%%~f"
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @set /a _count1+=1 >nul
    @setlocal enabledelayedexpansion
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param2_len%!///file///1///2///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param2_len%!///file///1///2///!_size!"
        ) else (
            @echo "!_current_path:~%_param2_len%!///file///1///2///-1"
        )
    )
    @endlocal
)
@popd>nul
@title Please wait...
@chcp 437>nul
@endlocal & (
    @set _count1=%_count1%
)
@goto :eof


:ProcedureProcessFilenamesLengthAndSize2
@setlocal
@REM Process hidden directories:
@for /f "tokens=*" %%f in ('title Loading hidden directory paths for directory 1. Please wait...^&@pushd "%_param1%"^>nul^&^&dir /a:dh /s /b 2^>nul^&^&popd^>nul^&title Please wait...') do @(
    @set "_current_path=%%~f"
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @set /a _count1+=1 >nul
    @setlocal enabledelayedexpansion
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param1_len%!///dir///0///1///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param1_len%!///dir///0///1///!_size!"
        ) else (
            @REM This file is hidden and probably has a Unicode path:
            @echo "!_current_path:~%_param1_len%!///dir///0///1///-1"
        )
    )
    @endlocal
)
@title Please wait...

@REM Process hidden directories:
@for /f "tokens=*" %%f in ('title Loading hidden directory paths for directory 2. Please wait...^&@pushd "%_param2%"^>nul^&^&dir /a:dh /s /b 2^>nul^&^&popd^>nul^&title Please wait...') do @(
    @set "_current_path=%%~f"
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @set /a _count1+=1 >nul
    @setlocal enabledelayedexpansion
    @set /a _count1+=1 >nul
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param2_len%!///dir///0///2///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param2_len%!///dir///0///2///!_size!"
        ) else (
            @REM This file is hidden and probably has a Unicode path:
            @echo "!_current_path:~%_param2_len%!///dir///0///2///-1"
        )
    )
    @endlocal
)
@title Please wait...

@REM Process hidden files:
@for /f "tokens=*" %%f in ('title Loading hidden file paths for directory 1. Please wait...^&@pushd "%_param1%"^>nul^&^&dir /a:-dh /s /b 2^>nul^&^&popd^>nul^&title Please wait...') do @(
    @set "_current_path=%%~f"
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @set /a _count1+=1 >nul
    @setlocal enabledelayedexpansion
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param1_len%!///file///0///1///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param1_len%!///file///0///1///!_size!"
        ) else (
            @REM This file is hidden and probably has a Unicode path:
            @echo "!_current_path:~%_param1_len%!///file///0///1///-1"
        )
    )
    @endlocal
)
@title Please wait...

@REM Process hidden files:
@for /f "tokens=*" %%f in ('title Loading hidden file paths for directory 2. Please wait...^&@pushd "%_param2%"^>nul^&^&dir /a:-dh /s /b 2^>nul^&^&popd^>nul^&title Please wait...') do @(
    @set "_current_path=%%~f"
    @set /a _count1+=1 >nul
    @if "%%~zf" == "" (
        @call :GenerateShortName _short_name "%%~f"
        @call :GenerateShortNameSize _size "%%_short_name%%"
    )
    @setlocal enabledelayedexpansion
    @title Processing file !_count1!...
    @if not "%%~zf" == "" (
        @echo "!_current_path:~%_param2_len%!///file///0///2///%%~zf"
    ) else (
        @if not "!_size!" == "" (
            @echo "!_current_path:~%_param2_len%!///file///0///2///!_size!"
        ) else (
            @REM This file is hidden and probably has a Unicode path:
            @echo "!_current_path:~%_param2_len%!///file///0///2///-1"
        )
    )
    @endlocal
)
@title Please wait...
@endlocal & (
    @set _count1=%_count1%
)
@goto :eof


:DisplayHelp
echo.
echo %~n0 ^(Cmd COMPare^) - Compare two directory trees by file and folder paths and by size
echo.
echo Syntax: %~n0 ^<dir_tree1^> ^<dir_tree2^>
echo.
echo - where ^<dir_tree1^> and ^<dir_tree2^> are two directory trees to be compared, provided by the user
echo.
echo * Note 1:
echo - Files that are hidden and also have a Unicode path - are compared only by path, not also by size
echo - In some rare cases ^(for some Unicode file paths^) some files may be misreported
echo.
echo * Note 2:
echo - This program uses the ^"sort^" utility for sorting results, so the waiting time for the comparison of the two directories depends on (is a multiple of) n * log n ^(the time complexity for the quick sort algorithm ^(used in ^"sort^"^)^) - where - n is the total number of files in the two directories that are to be compared.
echo - The output of the program is Unicode
goto :eof

:PressAKey
set /p=%~1<nul
pause>nul
goto :eof

Once you have saved ccomp.cmd, you can run it from the command prompt.

Running the Folder Comparison Script

  1. Open Command Prompt: Press Win + R, type cmd, and press Enter.

  2. Navigate to the script location: Use the cd command to navigate to the directory where you saved ccomp.cmd. For example, if you saved it in your Documents folder, you would type cd Documents and press Enter.

  3. Execute the script: Use the following syntax to compare two folders:

    ccomp <directory_path_1> <directory_path_2>

    Replace <directory_path_1> and <directory_path_2> with the actual paths to the folders you want to compare. For instance, to compare FolderA and FolderB located in your Documents directory, the command would be:

    ccomp DocumentsFolderA DocumentsFolderB
  4. Review the Output: The script will output the comparison results in the command prompt. The output will indicate:

    • “Only in [directory number] – [file type]: [path]”: This indicates files or folders that are present in only one of the specified directories. [directory number] will be “1” for the first directory and “2” for the second. [file type] will be either “file” or “dir”.
    • “[path] ([directory number]) size ([size1]B) is [bigger/smaller] than [path] ([directory number]) size ([size2]B)”: This indicates files that exist in both directories but have different sizes.

Example Scenarios

  • Identifying new files in a backup: Suppose you have a backup folder and want to quickly see which new files have been added to your main folder since the last backup. You can compare your main folder with the backup folder using ccomp.cmd. Any files listed as “Only in 1” (assuming your main folder is the first parameter) are the new files.
  • Checking for inconsistencies between mirrored folders: If you maintain mirrored folders and suspect inconsistencies, ccomp.cmd can help you pinpoint files or folders that are not identical in both locations.
  • Verifying folder synchronization: After using a synchronization tool, you can use ccomp.cmd to confirm that the folders are indeed synchronized and identify any remaining differences.

Important Considerations

  • UNC Paths: The script does not directly support UNC (Universal Naming Convention) paths (network paths starting with \). However, you can map a UNC path to a drive letter using the pushd command in the command prompt to work around this limitation.
  • Hidden and Unicode Paths: Files that are both hidden and have Unicode paths might only be compared by path, not by size, due to limitations in retrieving size information for such files in certain scenarios.
  • Sorting: The script uses the sort utility, so the comparison time will depend on the number of files and folders being processed. For very large directories, the process might take some time.

Conclusion

The ccomp.cmd script provides a handy command-line method to windows compare two folders. It’s a lightweight and efficient tool for quickly identifying differences in file paths and sizes, making it a valuable asset for system administrators, developers, and any Windows user who needs to manage and compare directories effectively. By understanding its usage and limitations, you can leverage this script to streamline your folder comparison tasks and maintain data consistency with ease.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *