Перечислите папки на или ниже заданной глубины в Powershell - PullRequest
2 голосов
/ 06 марта 2019

У меня есть каталог, который содержит много папок.Я хочу перечислить все папки (пути), которые идут глубже, чем на 2 уровня.Поэтому в папке ниже 1 и 2.

Directory/folder1
Directory/folder1/test1/test/testsub
Directory/folder1/test2
Directory/folder1/test3
Directory/folder2/blablabla/bla/1
Directory/folder3/test
Directory/folder4/test
Directory/folder5/test

Я пробовал следующее:

$Depth = 3
$Path = "."

$Levels = "\*" * $Depth
$Folder = Get-Item $Path
$FolderFullName = $Folder.FullName
Resolve-Path $FolderFullName$Levels | Get-Item | ? {$_.PsIsContainer} | Write-Host

Ответы [ 2 ]

1 голос
/ 06 марта 2019

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

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


Ваш умный подход, основанный на шаблонах, должен работать в принципе, но:

  • (а) это может быть значительно упрощено.

  • (b) требуется дополнительная работа, чтобы ограничить вывод отдельным списком тех дочерних папок, поддеревья которых слишком глубоки.

(a) Оптимизация вашего подхода:

$Depth = 3
$Path = '.'

$Levels = '/*' * $Depth
Get-ChildItem -Directory $Path/$Levels
  • Как и в вашем собственном подходе, '/*' * $Depth динамически создает групповое выражение уровня нескольких каталогов (например, /*/* для $Depth из 2), которое может быть добавлено к входу $Path соответствовать только путям на этом уровне.

  • Переключатель -Directory (PSv3 +) ограничивает соответствие только для каталогов.

(b) Ограничение вывода отдельным набором папок верхнего уровня со слишком глубокими поддеревьями:

$Depth = 3
$Path = '.'

$Levels = '/*' * $Depth
Get-ChildItem -Directory $Path/$Levels |
  ForEach-Object { ($_.FullName -split '[\\/]')[-$Depth] } |
    Select-Object -Unique

Примечание. Разделение по [/\\], то есть по / или \, делает решение работоспособным и на Unix-подобных платформах (PowerShell Core ); в Windows достаточно -split '\\' (через экранированный \).

При использовании вашей иерархии папок с примерами приведенное выше даст:

folder1
folder2
  • Если вы хотите вместо полные пути , добавьте
    | Convert-Path -LiteralPath { "$Path/$_" }.

  • Если вы хотите объекты каталогов ([System.IO.DirectoryInfo]) вместо этого, добавьте
    | Get-Item -LiteralPath { "$Path/$_" }.


Необязательное чтение: получение папок до, на или за определенной глубиной:

Примечание:

  • Несмотря на то, что указанные ниже решения предназначены для папок (каталогов), вы также можете включить файлов , просто пропустив -Directory, или целевые файлы только заменив -Directory с -File.

  • Для простоты команды неявно ориентированы на текущий каталог.


At-a- только для заданной глубины логика:

Это та же логика, что и в приведенном выше решении; следующий код перечисляет папки на глубине 2 только , то есть на уровне внука (дочерние каталоги дочерних каталогов) - обратите внимание, что, в отличие от Get-ChildItem -Depth, подсчет глубины начинается с 1, то есть 1 относится к дочерним каталогам:

$depth = 2 # grandchild directories only

Get-ChildItem -Directory -Path ('*/' * $depth)
  • Чтобы вывести полные пути , заключите команду Get-ChildItem в (...).FullName или перенаправьте ее на Select-Object -ExpandProperty FullName.

  • Для вывода относительных путей (например, folder1/test1/test/testsub) требуется дополнительная работа, поскольку добавление -Name будет не работать в этом случае, как ожидается (это выведет только каталог names ):

$depth = 2 # grandchild directories

# Calculate the length of the path prefix for determining relative paths.
# (Using the current dir ($PWD) as the reference path here.)
$PrefixLen = (Convert-Path -LiteralPath $PWD).Length + 1

$Levels = '/*' * $Depth
Get-ChildItem -Directory -Path ('*/' * $depth) |
  ForEach-Object { $_.FullName.Substring($PrefixLen) }

До логика заданной глубины:

Параметр PSv5 + -Depth ограничивает глубину рекурсии Get-ChildItem , т. Е. Он находит элементы только до указанной глубины, но учтите, что это глубина 0, а не 1, представляющая непосредственных детей .
Обратите внимание, что использование -Depth подразумевает -Recurse, хотя вы также можете указать и последнее.

Например, для перечисления дочерних папок и папок внуков (2 уровня) в текущем каталоге используйте:

$depth = 2 # child and grandchild directories

Get-ChildItem -Directory -Depth ($depth - 1)
  • Чтобы вывести полные пути , заключите команду Get-ChildItem в (...).FullName или перенаправьте ее на Select-Object -ExpandProperty FullName.

  • Для вывода относительных путей просто добавьте переключатель -Name к вызову Get-ChildItem.

At-a- заданная глубина-или-глубже логика:

Ограничение результатов элементами на уровнях, превышающих или равных заданной глубине, требует специального решения:

$depth = 2 # grandchild directories and below

Get-ChildItem -Directory -Name -Recurse |
  Where-Object { ($_ -split '[/\\]').Count -ge 2 } |
    Get-Item -LiteralPath { "$PWD/$_" }

Если ваш входной путь не является (подразумеваемым) текущим направлением, замените этот путь на $PWD.

  • Для вывода полных путей , замените Get-Item на Convert-Path.

  • Для вывода относительных путей , просто пропустите вызов Get-Item.

0 голосов
/ 06 марта 2019

Пожалуйста, попробуйте это

$Folders = Get-ChildItem 'C:\Program Files' -Directory -Recurse -Depth 1 | 
     Select-Object -ExpandProperty fullname | 
     Sort-Object
$Folders
...