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

19

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

dir /b /s /AD > c:\temp\dir_list.txt

这几乎给了我需要的列表。但是由于某些文件夹有很多子文件夹,而我不想在我的列表中看到它们,所以数据太多了。

有没有可能将该命令的递归深度限制为3(例如)?

c:\dir_1\dir_2\dir_3\dir_foo

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

也许可以不用批处理或VB脚本吗?


1
限制 Get-ChildItem 递归深度。 - n00b
6个回答

23
在这么长的时间里(5年),我现在才偶然发现一条简单的命令行一行命令,而这个命令一直可用。 ROBOCOPY自Vista以来一直是标准的Windows实用工具,并可通过Windows资源套件提供给XP使用。
robocopy . . /l /s /njh /njs /ns /lev:4 >c:\temp\dir_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.
< p > /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:\temp\dir_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:\temp\dir_list.txt

但是这个命令打起来有点麻烦。将这个技巧应用到一个实用的批处理文件中,只需要将根路径和层数作为参数即可。如果你将该命令放在批处理脚本中,请记得将百分号加倍。


1
嗨!+1 因为我喜欢 Robocopy 和你的专注。但我更喜欢使用你的第一个解决方案(它更具表现力)。 - Sauer

22
我相信可以编写一个复杂的命令来列出n级目录,但很难记住语法且容易出错。每次想要更改级别时都需要更改命令。使用简单的脚本会更好。
编辑5年后 - 实际上,自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

2
很好!运行良好。不过有一个小的“bug”。如果遇到一个系统无法访问的文件夹,它会向上跳转一个目录,然后使用旧的列表进行操作。但我不在意这个问题!还是非常感谢!这正是我想要的! - Sauer
1
@Sauer - 诊断错误的工作做得很好 :-) 我已经修复了代码以消除该错误。 - dbenham
我们如何做到包括隐藏文件夹? - Chef Gladiator
@dbenham 给了我灵感,谢谢... 正确的命令是 'DIR /B /S /A:HD' -- 这将列出当前目录下的隐藏目录。 - Chef Gladiator
@dbenham 是的,我正要自己添加那个。此外,/A:D-S会列出所有文件夹,但不包括系统文件夹。但是我注意到如果我添加了/S,那么-S将被忽略? - Chef Gladiator
显示剩余2条评论

6
这里提供一种基于@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

3

这是对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 ... 中可以设置缩进字符。


0

我对elady的版本进行了改进:

  • 默认情况下,minLevel为maxLevel-1
  • 更改了参数顺序:maxLevel、minLevel、curFolder。这样默认的目标路径就是当前路径,更方便。可以通过三种不同的方式调用:
    • 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

0
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文件夹。 -名称使命令仅显示文件夹的裸名,而不是站点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接