Установите Recursive-Depth для команды dir в dos

В настоящее время я использую следующую команду, чтобы перечислить некоторые каталоги:

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

Это дает мне почти список, который мне нужен. Но это слишком много данных, потому что некоторые папки имеют очень много подпапок, которые я не хочу видеть в своем списке.

Можно ли ограничить глубину рекурсии команды -lets скажем- 3?

c:\dir_1\dir_2\dir_3\dir_foo

Поэтому, если я выполню команду в приведенном выше примере в c:>, я не хочу видеть каталог dir_foo, а только каталог dir_n...

Может, без пакетного /vb-скрипта?

6 ответов

Решение

Я уверен, что можно написать сложную команду, которая бы перечисляла 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

После всего этого времени (5 лет), и я только сейчас наткнулся на простую командную строку один лайнер, который был доступен все время. ROBOCOPY была стандартной утилитой Windows начиная с Vista, и доступна для XP через Windows Resource Kit.

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.

/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

Но команда становится немного неловко набирать. Должно быть легко включить эту технику в пакетный файл утилиты, который принимает корневой путь и уровень в качестве аргументов. Не забывайте удваивать проценты, если вы помещаете команду в пакетный скрипт.

Вот решение, которое основано на глубоком первом листинге решения @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 ...

      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 папки от корня. -Exclude Recycle не должен отображать папку $Recycle.bin. -Name заставляет команду показывать имена папок; тоже не станция.

Моя доработанная версия по сравнению с elady's:

  • minLevel по умолчанию maxLevel-1
  • изменен порядок параметров: maxLevel, minLevel, curFolder. Таким образом, target_path по умолчанию является текущим путем, что более удобно. Звонить можно 3 способами:
    • 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
Другие вопросы по тегам