如何为Windows命令DIR设置递归深度



我目前正在使用以下命令列出一些目录:

dir /b /s /AD > c:tempdir_list.txt

这给了我几乎需要的清单。但数据太多了,因为有些文件夹有很多我不想在列表中看到的子文件夹。

是否可以将命令的递归深度限制为3(例如)?

c:dir_1dir_2dir_3dir_foo

因此,如果我在c:>中执行上面示例中的命令,我不想看到目录dir_foo,而只想看到dir_n

也许没有批处理或VB脚本?

经过这么长时间(5年),我刚刚偶然发现了一个一直可用的简单命令行一行。ROBOCOPY自Vista以来一直是标准的Windows实用程序,XP可以通过Windows资源工具包使用它。

robocopy . . /l /s /njh /njs /ns /lev:4 >c:tempdir_list.txt

解释

/L :: List only - don't copy, timestamp or delete any files.
/S :: copy Subdirectories, but not empty ones.
/NJH :: No Job Header.
/NJS :: No Job Summary.
/NS :: No Size - don't log file sizes.
/LEV:n :: only copy the top n LEVels of the source directory tree.

/lev:n选项在计数中包括根,并且您需要3个子目录级别,这就是我在值中添加1的原因。

正在进一步处理

输出并不完美,因为根文件夹包含在输出中,并且每个路径都包含固定宽度的前导空格。使用FOR /F可以方便地消除根路径以及前导空格。

(for /f "skip=2 tokens=*" %A in ('robocopy . . /l /s /njh /njs /ns /lev:4') do @echo %A) >c:tempdir_list.txt

ROBOCOPY输出包含一个初始空行,这就是为什么skip必须是2而不是1。

每条路径将以结束。我喜欢这个功能,因为它清楚地表明我们列出的是文件夹而不是文件。如果您真的想消除尾随的,那么您可以添加一个额外的FOR

(for /f "skip=2 tokens=*" %A in ('robocopy . . /l /s /njh /njs /ns /lev:4') do @for %B in ("%A.") do @echo %~fB) >c:tempdir_list.txt

但是这个命令输入起来有点笨拙。将此技术合并到以根路径和级别为参数的实用程序批处理文件中应该很容易。如果将命令放入批处理脚本中,则必须记住将百分比加倍。

我确信可以编写一个列出n级目录的复杂命令。但是很难记住语法,而且容易出错。每次您想要更改级别的数量时,它也需要进行更改。

使用简单的脚本要好得多。

EDIT 5 Years Later -实际上,从Vista开始就有一个简单的单行。查看我的新ROBOCOPY解决方案

下面是一个执行深度优先列表的批处理解决方案。DIR/S命令执行广度优先的列表,但我更喜欢这种深度优先的格式。

@echo off
setlocal
set currentLevel=0
set maxLevel=%2
if not defined maxLevel set maxLevel=1
:procFolder
pushd %1 2>nul || exit /b
if %currentLevel% lss %maxLevel% (
for /d %%F in (*) do (
echo %%~fF
set /a currentLevel+=1
call :procFolder "%%F"
set /a currentLevel-=1
)
)
popd

广度优先的版本几乎相同,只是它需要一个额外的FOR循环。

@echo off
setlocal
set currentLevel=0
set maxLevel=%2
if not defined maxLevel set maxLevel=1
:procFolder
pushd %1 2>nul || exit /b
if %currentLevel% lss %maxLevel% (
for /d %%F in (*) do echo %%~fF
for /d %%F in (*) do (
set /a currentLevel+=1
call :procFolder "%%F"
set /a currentLevel-=1
)
)
popd

两个脚本都需要两个参数:

arg1=要列出的根目录的路径

arg2=要列出的级别数。

因此,要列出当前目录的3个级别,可以使用

listDirs.bat . 3

要列出不同目录的5个级别,可以使用

listDirs.bat "d:my folder" 5

这是一个基于@dbenham的深度优先列表解决方案的解决方案,
并且能够设置最小级别

@echo off
setlocal
set currentLevel=0
set maxLevel=%2
if not defined maxLevel set maxLevel=1
set minLevel=%3
if not defined minLevel set minLevel=0
:procFolder
pushd %1 2>nul || exit /b
if %currentLevel% lss %maxLevel% (
for /d %%F in (*) do (
if %currentLevel% geq %minLevel% echo %%~FF
set /a currentLevel+=1
call :procFolder "%%F"
set /a currentLevel-=1
)
)
popd

要设置最低级别,只需将其作为第三个参数
例如:要从2级列表到5级,可以使用

listDirs.bat target_path 5 2

或者,您可以通过将此参数留空从基本级别列出

listDirs.bat target_path 5

这是对dbenham(和elady)的解决方案的一点增强。它根据深度缩进输出。它显著提高了可读性

@echo off
setlocal
set currentLevel=0
set maxLevel=%2
if not defined maxLevel set maxLevel=1
set minLevel=%3
if not defined minLevel set minLevel=0
:procFolder
pushd %1 2>nul || exit /b
set "indent=."
if %currentLevel% lss %maxLevel% (
for /d %%F in (*) do (
for /l %%i in (1,1,%currentLevel%) do echo|set /p=%indent%
if %currentLevel% geq %minLevel% echo %%~fF
set /a currentLevel+=1
call :procFolder "%%F"
set /a currentLevel-=1
)
)
popd

可以在set "indent ...中设置缩进字符

我对elady的改进版本:

  • minLevel默认为maxLevel-1
  • 更改了参数的顺序:maxLevel,minLevel,curFolder。这样,默认的target_path是当前路径,更方便。一个人可以用三种不同的方式打电话:
    • listDirs.bat 2(直上)
    • listDirs.bat 2 0(差异最低级别,请尝试查看)
    • listDirs.bat 2 0 target_path(需要时使用完整语法)
@echo off
setlocal
set currentLevel=0
set maxLevel=%1
if not defined maxLevel set maxLevel=1
set minLevel=%2
if not defined minLevel set /a minLevel=%maxLevel%-1
:procFolder
pushd %3 2>nul || exit /b
if %currentLevel% lss %maxLevel% (
for /d %%F in (*) do (
if %currentLevel% geq %minLevel% echo %%~fF
set /a currentLevel+=1
call :procFolder %maxLevel% %minLevel% "%%F"
set /a currentLevel-=1
)
)
popd
set "drive=C:" 
for /F "usebackq tokens=* delims=" %%a in (`PowerShell.exe -Command "&{Get-ChildItem -Path %drive% -Exclude *Recycle* -Recurse -Depth 2 -Name -Directory}"`) do ( 
echo.[%%a] 
) 

-深度2应将文件夹递归限制在距离根目录3个文件夹的深度。-排除回收不应显示$Recycle.bin文件夹。-Name使命令显示文件夹的裸名称;而不是车站。

最新更新