如何从 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%
即对目标进行目录名扫描;如果找到的目录不是排除名称,则对该子目录执行其余操作。
现在我有一个批处理脚本,用于遍历一堆子文件夹,并将其中的日志文件压缩,文件夹结构基本上是这样的:
+---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%
即对目标进行目录名扫描;如果找到的目录不是排除名称,则对该子目录执行其余操作。