我希望查看文件夹中任何子目录中的最大子目录数。 即,
Folder==>
SubA==>
b.xlsx
SubB==>
SubB.C==>
b.c.xlsx
这样会返回(2),因为SubB.C是两个文件夹深。
我试过
set count=
for /d %%a in (U:\*) do set /a count+=1
echo %count%
但这次递归让我很难过。我无法进入第二/第三/第四级子目录。
答案 0 :(得分:3)
我不知道性能,(只有大目录树的问题),但您也可以尝试从批处理文件中使用基于PowerShell
的方法:
@Echo Off
CD /D "U:\" 2>Nul || Exit /B
PowerShell -NoL -NoP "GCI .\ -R|?{$_.PSIsContainer}|Select @{Name='FullName';Expression={$_.FullName.Replace($PWD,'')}},@{Name='FolderDepth';Expression={($_.FullName.Split('\').Count)-($PWD.Path.Split('\').Count)}}|Sort -Des FolderDepth|Select -F 1 -Exp FolderDepth"
Pause
修改 (以满足点燃评论中的要求):
@Echo Off
CD /D "U:\" 2>Nul || Exit /B
Set "MaxLevels="
For /F %%A In ('
PowerShell -NoL -NoP "GCI .\ -R|?{$_.PSIsContainer}|Select @{Name='FullName';Expression={$_.FullName.Replace($PWD,'')}},@{Name='FolderDepth';Expression={($_.FullName.Split('\').Count)-($PWD.Path.Split('\').Count)}}|Sort -Des FolderDepth|Select -F 1 -Exp FolderDepth"
') Do Set "MaxLevels=%%A"
Set MaxLevels 2>Nul
Pause
答案 1 :(得分:3)
您可以破解JREPL.BAT(正则表达式文本处理器)来计算每个路径中的反斜杠数。我首先列出根文件夹,以便我可以从max中减去该值,以获得根文件夹中的最大子文件夹深度。
@echo off
pushd %1
(cd & dir /b /s /ad) | jrepl "\\" "$txt=false;n++" ^
/JMATCHQ ^
/JBEG "var n, root, max=0" ^
/JBEGLN "n=0" ^
/JENDLN "if (ln==1) root=n; if (n>max) max=n" ^
/JEND "output.writeLine(max-root)"
popd
我使用了很多^
行继续来使代码易于阅读而无需水平滚动。
如果要在变量中捕获结果,那么最简单的解决方案是将CD和DIR输出写入临时文件,并使用JREPL / RTN选项保存结果。
@echo off
setlocal
set "file=%temp%\folders.txt"
pushd %1
(cd & dir /b /s /ad) >"%file%"
popd
call jrepl "\\" "$txt=false;n++" /F "%file%" ^
/JMATCHQ ^
/JBEG "var n, root, max=0" ^
/JBEGLN "n=0" ^
/JENDLN "if (ln==1) root=n; if (n>max) max=n" ^
/JEND "output.writeLine(max-root)" ^
/RTN count
del "%file%"
echo %count%
在我的机器上,我的代码运行速度是Compo的PowerShell解决方案的两倍,并且比aschipfl递归纯批处理解决方案快得多
。这是一个不需要JREPL.BAT的混合JScript /批处理解决方案
@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
::--- Batch section within JScript comment that calls the internal JScript ----
@echo off
pushd %1 || exit /b
(cd & dir /b /s /ad) | cscript //E:JScript //nologo "%~f0"
popd
exit /b
----- End of JScript comment, beginning of normal JScript ------------------*/
var root=0, max=0, level;
while( !WScript.StdIn.AtEndOfStream ) {
level=WScript.StdIn.ReadLine().split('\\').length-root;
if (!root) root=level;
if (level>max) max=level;
}
WScript.StdOut.WriteLine(max);
如果要在变量中捕获结果,则可以使用FOR / F循环:
@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
::--- Batch section within JScript comment that calls the internal JScript ----
@echo off
pushd %1 || exit /b
for /f %%A in ('(cd ^& dir /b /s /ad^) ^| cscript //E:JScript //nologo "%~f0"') do set depth=%%A
popd
set depth
exit /b
----- End of JScript comment, beginning of normal JScript ------------------*/
var root=0, max=0, level;
while( !WScript.StdIn.AtEndOfStream ) {
level=WScript.StdIn.ReadLine().split('\\').length-root;
if (!root) root=level;
if (level>max) max=level;
}
WScript.StdOut.WriteLine(max);
答案 2 :(得分:2)
您需要为该任务使用某种递归。如何循环子目录并为每个子目录调用自身的子例程呢?我的意思是:
@echo off
rem // Define constants here:
set "_PATH=%~1" & rem // (path of the root directory to process)
rem // Define global variables here:
set /A "$DEPTH=0" & rem // (variable to determine the greatest depth)
rem // Initialise variables:
set /A "DEEP=0" & rem // (depth of the current directory branch)
rem // Call recursive sub-routine, avoid empty argument:
if defined _PATH (call :SUB "%_PATH%") else (call :SUB ".")
rem // Return found depth:
echo %$DEPTH%
exit /B
:SUB <root_path>
rem // Loop through all sub-directories of the given one:
for /D %%D in ("%~1\*") do (
rem // For each sub-directory increment depth counter:
set /A "DEEP+=1"
rem // For each sub-directory recursively call the sub-routine:
call :SUB "%%~fD"
)
rem // Check whether current branch has the deepest directory hierarchy:
if %$DEPTH% lss %DEEP% set /A "$DEPTH=DEEP"
rem // Decrement depth counter before returning from sub-routine:
set /A "DEEP-=1"
exit /B
作为另一种想法,但性能稍差,您还可以确定所有子目录的已解析路径中的反斜杠数(\
),检索最大数量并减去该数量最大的根目录,如下所示:
@echo off
rem // Define constants here:
set "_PATH=%~1" & rem // (path of the root directory to process)
rem // Define global variables here:
set /A "$DEPTH=0" & rem // (variable to determine the greatest depth)
rem // Change to root directory:
pushd "%_PATH%" || exit /B 1
rem // Resolve root directory:
call :SUB "."
rem // Store total depth of root directory:
set /A "CROOT=$DEPTH, $DEPTH=0"
rem // Process all sub-directories recursicely:
for /D /R %%D in ("*") do (
rem // Determine greatest depth relative to root:
call :SUB "%%~fD" -%CROOT%
)
rem // Change back to original directory:
popd
rem // Return found depth:
echo %$DEPTH%
exit /B
:SUB <val_path> [<val_offset>]
rem // Resolve provided sub-directory:
set "ITEM=%~f1" & if not defined ITEM set "ITEM=."
rem // Initialise variables, apply count offset:
set "COUNT=%~2" & set /A "COUNT+=0"
rem // Count number of backslashes in provided path:
for %%C in ("%ITEM:\=" "%") do (
set /A "COUNT+=1"
)
rem // Check whether current branch has the deepest directory hierarchy:
if %$DEPTH% lss %COUNT% set /A "$DEPTH=COUNT"
exit /B