PowerShell Get-ChildItem результат в массиве
(Get-ChildItem -File -Recurse -Path $path).Fullname
возвращает массив полных имен
(Get-ChildItem -File -Recurse -Path $path).Name
возвращает массив имен файлов, но
(Get-ChildItem -File -Recurse -Path $path).Length
возвращает только одно значение - количество элементов
Вопрос - как получить результат в виде массива длин файлов?
3 ответа
В дополнение к полезному ответу Матиаса Р. Джессена :
tl;dr
Использование позволяет получить краткое и эффективное решение:
(Get-ChildItem -File -Recurse -Path $path).ForEach('Length')
Как указано в ответе Матиаса, свойства, присущие типу, например, в экземплярах массива, имеют приоритет над так называемым перечислением членов, которое было вашим намерением, то есть вы хотели собрать
.Length
значения свойств элементов вашей коллекции (массива) и вернуть их как (
[object[]]
) массив .
- В выпуске GitHub № 7445 обсуждается эта ситуационная неоднозначность и предлагается ввести специального оператора , например
%.
так что вы можете однозначно запросить либо обычный доступ к свойству, либо перечисление членов.
Возможно, удивительным аспектом перечисления членов является то, что оно применяет конвейерную логику, которая ситуативно возвращает скаляр , а именно, если коллекция содержит только один элемент .
- Например,
@(Get-Date).Year.GetType().Name
возвращаетSystem.Int32
, нетObject[]
, что указывает на то, что было возвращено целое число, а не (одноэлементный) массив, содержащий целое число. - обсуждается в Этовыпуске GitHub № 6802 .
Перечисление членов не только удобно, но и быстро , поскольку позволяет избежать цикла / перечисления в коде PowerShell .
Использование ForEach-Object
или же Select-Object
Командлеты , как показано в ответе Матиаса, определенно являются функциональным, но медленным решением из-за использования конвейера , который не требуется для ввода, который уже находится в памяти полностью .
Таким образом, использование в метода массивамассиве методом - с помощью перегрузки , где вы просто указать целевое свойство имя (
'Length'
) - краткая и более эффективная альтернатива .
- Примечание. В отличие от перечисления членов, возвращаемое значение из
.ForEach()
это всегда коллекция , хотя и не является массивом : он имеет тип[System.Collections.ObjectModel.Collection[psobject]]
, который, однако, в большинстве случаев будет вести себя как массив. [1]
[1] В отличие от массива, этот тип коллекции является расширяемой (вы можете добавлять или удалять элементы). Из-за того, что тип элемента
[psobject]
, каждый элемент обычно невидимо заключен в этот тип; например,
42 -is [psobject]
является
$false
, но
@(42).ForEach({ $_ })[0] -is [psobject]
является
$true
. К сожалению, бывают случаи, когда эта почти невидимая оболочка приводит к другому поведению - см. Проблему GitHub #5579.
Единственное значение, которое вы получаете, действительно является длиной результирующего массива - класс Array имеет явное свойство, которое имеет приоритет над перечислением свойств.
Чтобы получить человека
Length
значения свойств из каждого элемента в массиве, по конвейеру либо
Select-Object
или же
ForEach-Object
, вот так:
Get-ChildItem -File -Recurse -Path $path |ForEach-Object -MemberName Length
# or
Get-ChildItem -File -Recurse -Path $path |Select-Object -ExpandProperty Length
В вашем примере вы получаете результирующий массив.
Get-ChildItem -File
возвращает массив
System.IO.FileInfo
. Итак, вам нужно взять (выбрать) атрибут каждой записи в массиве. Это делается с помощью
Select-Object
или просто
select
:
Get-ChildItem -File -Recurse -Path $path | Select-Object Length
который даст вам массив объектов, содержащих длину файла как
Length
имущество. Вы также можете выбрать несколько свойств:
Get-ChildItem -File -Recurse -Path $path | Select-Object Name, Length