如何从 dir 调用循环中排除目录——比 |find /v 更快

How to exclude a directory from a dir call loop--faster than |find /v

现在我有一个批处理脚本,用于遍历一堆子文件夹,并将其中的日志文件压缩,文件夹结构基本上是这样的:

+---fakeG
|   +---ExclusionFolder
|   |   +---LimitlessFolders
|   |   +---MoreFolders
|   |   \---SoManyFolders
|   +---logs1
|   +---logs2
|   +---logs3
|   +---logs4
|   +---logs5
|   \---logs6

必须遍历这些子文件夹中的每一个,并且还要遍历它们的子文件夹。这个脚本必须避开一个特定的文件夹,它确实避开了它,但它使用了 %|找到/v。尽管在此示例中,ExclusionFolder 位于列表的顶部,但在实际文件夹结构中并非如此。

这是我现在的做法:

FOR /F "delims=" %%A IN (
    'DIR "%LogsFilespec%" /B /S ^| find /v "ExclusionFolder"'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%

在 ExclusionFolder 中,有更多的子文件夹,可能还有更多的子文件夹,因此它会减慢必须进入每个子文件夹的脚本执行速度。

SO: 有没有更快的方法在不使用 |find 的情况下从目录调用中排除文件夹?

还是我必须想出一种完全不同的方法来做到这一点?

编辑 抱歉,%LogsFileSpec℅ 指的是目标文件。我原来的编辑是对的,我的第二次编辑是错误的。

SET LogsLocation="G:\fakeG\Data\Logs"
SET LogsName="trace*%targetDate%.log"
SET LogsFilespec="%LogsLocation%\%LogsName%"

抱歉没有给出更多的脚本,我觉得这个问题不需要太多。

Edit2 过程 :DoZip 是这样工作的:

:DoZip
:: Parameter 1 = Filename without .EXT for Archive Name
:: Parameter 2 = Target file specifics
:: Parameter 3 = Zip Command (Winzip/7zip64/7zip32)
:: Parameter 4 = Zip Parameters (a -tzip, -a)
:: Parameter 5 = ProcessLog
setlocal 
SET archiveName=%~1
SET SourceFileSpec=%~2
SET zipCommand=%~3
SET zipParms=%~4
SET RunLog=%~5

    ECHO %TIME% Archiving %SourceFileSpec%...
    ECHO %TIME% Archiving %SourceFileSpec%... >> %RunLog%

    ECHO "%zipCommand%" %zipParms% "%archiveName%.zip" "%SourceFileSpec%"
    ECHO "%zipCommand%" %zipParms% "%archiveName%.zip" "%SourceFileSpec%" >> %RunLog%
    "%zipCommand%" %zipParms% "%archiveName%.zip" "%SourceFileSpec%" >> %RunLog%

 :: Check errorlevel of executed command
 :: If errorlevel != 0, set EC with the errorlevel and echo that there was an error in archival
 IF NOT %ERRORLEVEL%==0 (
    ECHO ***ERROR archiving %SourceFileSpec% >>                                                                         %RunLog%
    SET EC=%ERRORLEVEL%
    ECHO ***ERRORLEVEL RETURNED: %EC% >> %RunLog%
) ELSE (
 :: Otherwise, delete the file
    ECHO. >>                                                                                                                            %RunLog%
    ECHO. >>                                                                                                                            %RunLog%
    ECHO %TIME% Deleting %SourceFileSpec%...
    ECHO %TIME% Deleting %SourceFileSpec%... >>                                                                         %RunLog%
 ::Quietly delete the file
    DEL /Q %SourceFileSpec%

    :: Set ErrorLevel to capture the Delete command result.
    SET EC=%ERRORLEVEL%
)
GOTO :EOF

编辑 3 这里是 zipCommand

SET PathWinZip=C:\Program Files\WinZip\wzzip.exe
SET Path7Zip_64bit=C:\Program Files-Zipz.exe
SET Path7Zip_32bit=C:\Program Files (x86)-Zipz.exe

:: Check for WinZip
IF EXIST "%PathWinZip%" SET zipCommand=%PathWinZip% & SET zipParms=-a 

:: Check for 32-bit version of 7-Zip. If found, configure
:: its command line parameter to produce a .zip file
IF EXIST "%Path7Zip_32bit%" SET zipCommand=%Path7Zip_32bit% & SET zipParms=a -tzip

:: Check for 64-bit version of 7-Zip. If found, configure
:: its command line parameter to produce a .zip file
IF EXIST "%Path7Zip_64bit%" SET zipCommand=%Path7Zip_64bit% & SET zipParms=a -tzip

这种方法可能会更快一些:

pushd "%LogsFilespec%"
rem get subfolders of first level only
for /f "tokens=*" %%p in (
  'DIR "%LogsFilespec%" /B /AD ^| find /v "ExclusionFolder"'
  ) do (  
    rem treat each (here will not be excluded one) 
    FOR /F "delims=" %%A IN (
      'DIR "%%~p" /B /S'
    ) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%
)
popd
goto :eof

下面的解决方案既不使用单个 FIND 命令也不使用 FOR /F ... 命令(需要执行 cmd.exe 的副本),所以我认为它应该 运行 更快:

@echo off
setlocal

rem Enter to the base folder
cd "%LogsFilespec%"

rem Start the recursive process
call :processThisDir
goto :EOF


:processThisDir

rem Process the files in this folder
for %%A in (*.*) do CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%

rem Process nested subfolders, but omit "ExclusionFolder"
for /D %%a in (*) do (
   if "%%a" neq "ExclusionFolder" (
      cd "%%a"
      call :processThisDir
      cd ..
   )
)
exit /B

我认为以下应该排除有问题的子树:

FOR /F "delims=" %%X IN (
    'DIR /B /ad ') DO IF /i "%%X" neq "ExclusionFolder" FOR /F "delims=" %%A IN (
    'DIR  /B /S "%%X\%LogsFilespec%"'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%

即对目标进行目录名扫描;如果找到的目录不是排除名称,则对该子目录执行其余操作。