29

Рассмотрим следующий скрипт Powershell, который ищет папки в C:\ с именем 'og':

PS C:\> (ls | %{$_.Name} | ?{$_.Contains("og")})
PerfLogs
Program Files
setup.log

Теперь я сужу поиск, чтобы получить только один элемент:

PS C:\> (ls | %{$_.Name} | ?{$_.Contains("Prog")})
Program Files

Странно то, что первая операция приводит к массиву, тогда как вторая операция (которая ИМХО семантически та же самая операция, поэтому она должна давать тот же тип результата) возвращает строку. Это можно увидеть в следующем результате:

PS C:\> (ls | %{$_.Name} | ?{$_.Contains("og")}).Length
3
PS C:\> (ls | %{$_.Name} | ?{$_.Contains("Prog")}).Length
13

Это может быть очень раздражающим, поскольку очевидно, что папок, которые соответствуют 'og', меньше, чем папок, которые соответствуют 'Prog'.

Очевидно, что PowerShell неявно «распаковывает» массив из одного элемента в один объект, и мы никогда не получаем массив длиной 1. Кажется, что каждый раз, когда я хочу подсчитать результаты, поступающие по конвейеру, я должен проверить, имею ли я дело с массивом или нет.

Как я могу предотвратить это? Как вы справляетесь с этим?

3 ответа3

47

Очевидно, что PowerShell неявно «распаковывает» массив из одного элемента в один объект,

И нулевой элемент приводит к $null .

Как я могу предотвратить это?

Ты не можешь

Как вы справляетесь с этим?

Используйте конструктор массива (@(...)) для принудительного возврата коллекции (возможно, с нулем или одним элементом):

$res = @(ls | %{$_.Name} | ?{$_.Contains("Prog")})
2

Это было решено в PowerShell v3:

http://blogs.microsoft.co.il/blogs/scriptfanatic/archive/2012/03/19/Counting-objects-in-PowerShell-3.0.aspx

В примечании вы можете найти, содержит ли имя что-то, используя подстановочный знак:

PS> ls *og*
1

Обратите внимание на разницу между этими двумя результатами:

PS C:\> ConvertTo-Json -InputObject @(1)
[
    1
]
PS C:\> @(1)|ConvertTo-Json
1
PS C:\>

Дело в том, что «распаковка» выполняется с помощью конвейера. ConvertTo-Json по-прежнему видит объект как массив, если мы используем InputObject, а не трубопровод.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .