web-dev-qa-db-ja.com

2つのフォルダーを比較し、不足しているファイルを両方のフォルダーに出力する

厳密にファイル名について、2つのフォルダを比較したいと思います。 (ファイルの内容ではない)。 Windows 10を使用していて、コマンドラインツールを使用したいと考えています。

これは問題を説明するかもしれないシナリオです。

Folders
-------
source                  source2 
   - file_1                 - file_1
   - file_2                 - file_2
   - file_3                 - file_4
   - file_5                 - file_5
   - file_6                 - file_7


Output should be:
-----------------
Source  -> Missing files file_4  
Source2 -> Missing files file_3  

いくつか調査しましたが、diffツールはたくさんありますが、ファイルの内容を比較することには興味がありません。 2つのフォルダーを比較し、両方のフォルダーで欠落しているファイルを(他のフォルダーと比較して)出力するだけです。

Powershellを使用したくない

ありがとうございました。

6
Gifcrazy

robocopy(最近のWindowsバージョンに含まれています)は、これを1つのパスで実行できます。

\source\\source2\を指定し、いくつかの一般的なファイルとどちらかのフォルダにのみ存在するファイルを実行

robocopy source source2 /L /NJH /NJS /NP /NS

収量

D:\Users\me\test\source\
         *EXTRA Datei                  only_in_source2.txt
           Neue Datei                  only_in_source.txt

ここで、*で始まる行はsource2(OS言語に依存しない)でのみファイルを示し、他の行はsourceでのみファイルを示します。

オプションはさまざまな出力項目を抑制し、/Lは相違点のみがリストされ、コピーされないように注意します。

7
user1016274

次のコードをccomp.cmdとして保存し、/?フラグを付けて呼び出して、その使用方法を確認します(Windows 7、Windows 10でテスト済み):

構文:

ccomp <dir_tree1> <dir_tree2>

コード:

@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%"
    popd>nul

    pushd "%_param2%\">nul
    set "_param2=%CD%"
    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 :ProcedureProcessFilenameLengthAndSize1
                    chcp 65001>nul
                    call :ProcedureProcessFilenameLengthAndSize2
                    chcp 437>nul

                    @REM After sorting: "-" is displayed in front of 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 - 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

:ProcedureProcessFilenameLengthAndSize1
    @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

:ProcedureProcessFilenameLengthAndSize2
    @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 an probabilly 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 an probabilly 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 an probabilly 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 an probabilly 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
    echo.
    echo     Written by: Ioan Marin
goto :eof

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

両方のフォルダーのdir /b /A-dofをファイルに対して実行し、これらをfindstrおよび/VG:オプションと比較します

サンプルツリーが与えられた場合:

> tree /f
X:.
│
└───Folders
    ├───source
    │       file_1
    │       file_2
    │       file_3
    │       file_5
    │       file_6
    │
    └───source2
            file_1
            file_2
            file_4
            file_5
            file_7

次のバッチファイル:

:: Q:\Test\2019\02\19\SU_1407481.cmd
@echo off

Set "DirA=X:\Folders\source\"
Set "DirB=X:\Folders\source2\"

Dir /B /A-D "%DirA%*" >DirA.txt
Dir /B /A-D "%DirB%*" >DirB.txt

echo file(s) missing in %DirA%
findstr /VG:DirA.txt DirB.txt

echo fil(e) missing in %DirB%
findstr /VG:DirB.txt DirA.txt

この出力を生成します:

> SU_1407481.cmd
file(s) missing in X:\Folders\source\
file_4
file_7
file(s) missing in X:\Folders\source2\
file_3
file_6
1
LotPings

このPowershellスクリプトはあなたが望むことをします。

$fso = Get-ChildItem -Recurse -path C:\Temp\Source
$fsoBU = Get-ChildItem -Recurse -path C:\Temp\Source2
Compare-Object -ReferenceObject $fso -DifferenceObject $fsoBU

これと他のいくつかのオプションについては、ここで説明します。 https://stackoverflow.com/questions/3804109/what-is-the-best-way-to-compare-2-folder-trees-on-windows

1
Doug Deden