Почему Powershell Array of Array отображает различное содержимое, если не назначено переменной - PullRequest
0 голосов
/ 12 января 2019

Если командлет возвращает массив массива, например:

function test() {
    $results = New-Object System.Collections.ArrayList
    $array = @()
    for ($idx = 0; $idx -lt 3; $idx++) {
         $obj = New-Object PSObject -Property @{
            "key1" = "value1";
         }
        $array += @($obj)
    }
    [Void] $results.add($array)
    return ,$results.TOArray()
}

Тогда выход будет другим, когда присваивается возвращаемое значение.

если запустить test напрямую, он отображает:

test


Length         : 3
LongLength     : 3
Rank           : 1
SyncRoot       : {@{key1=value1}, @{key1=value1}, @{key1=value1}}
IsReadOnly     : False
IsFixedSize    : True
IsSynchronized : False
Count          : 3

при присваивании переменной:

$result = test
$result

key1  
----  
value1
value1
value1

И если командлет возвращает массив с одним уровнем, выходные данные test и $(test) совпадают.

function test() {
    $array = New-Object System.Collections.ArrayList
    for ($idx = 0; $idx -lt 3; $idx++) {
         $obj = New-Object PSObject -Property @{
            "key1" = "value1";
         }
        $array += @($obj)
    }
    return ,$array
} 

test вывод:

key1  
----  
value1
value1
value1

1 Ответ

0 голосов
/ 13 января 2019

PetSerAl предоставил критический указатель в кратком комментарии:

Разница в рендеринге сводится к тому, что:

  • оператор test - это команда (вызов функции, командлета или внешней программы)
  • , тогда как $result (который ранее захватывал выходные данные test) является выражением (что-то, включающее только ссылки на переменные, операторы PowerShell и вызовы методов .NET, вне конвейер - хотя он может содержать вложенных команды).

Выводя , $results.ToArray() из функции test (функция является одной из форм команды), вы используете ,, оператор построения массива, для переноса $results.ToArray() (что приводит к массиву массивов) во вспомогательном, временном одноэлементном массиве, который является обычной техникой, гарантирующей, что коллекция передается как одиночный объект , а не перечисляется его элементов .

То есть aux. Массив-оболочка :

  • неизменно теряется при выводе в конвейер , из-за поведения автоматического развертывания (развертывания) конвейера,

  • , но гарантирует, что массив в оболочке будет рассматриваться как отдельный объект при следующей команде в конвейере .

Концептуально более четкий, но более подробный эквивалент , $results.ToArray() внутри вашей функции - Write-Output -NoEnumerate $results.ToArray(); то есть обычно неявный вывод PowerShell делается явным, с запросом на подавление поведения по умолчанию перечисления выходных коллекций.

Учитывая, что в конвейере нет дополнительной команды, вывод tests неявно выводится на экран . В данном случае печать массива массивов как одного объекта приводит к форматированию вывода списка свойств, которое вы видели.

Напротив, $result, поскольку выражение равно , неявно пронумеровано . То есть массив массивов, захваченных из test - без вспомогательного. массив обёрток! - отправляется один элемент за раз в систему форматирования вывода, и эти элементы затем визуализируются более осмысленно.


Чтобы предоставить более простой пример :

Предположим, что ваша функция test использует return , , (1..3) для вывода массива контейнера, содержащего массив из 3 элементов, который, наконец, обернут в aux. одноэлементный массив (как отступление: return в PowerShell - это просто синтаксический сахар для выхода из блока функции или скрипта, он не имеет прямой связи с тем, что output ).

Выполнение функции test эквивалентно прямому выполнению следующего выражения :

, , (1..3)

То есть внешнее, aux. массив снова отбрасывается из-за неявного перечисления, и , (1..3) отображается как отдельный объект , что приводит к формату списка свойств:

Length         : 3
LongLength     : 3
Rank           : 1
SyncRoot       : {1, 2, 3}
IsReadOnly     : False
IsFixedSize    : True
IsSynchronized : False
Count          : 3

Напротив, выполнение $result (после запуска $result = test) эквивалентно просто:

, (1..3)

То есть внешнее, aux. массив был потерян во время $result = test, контейнерный массив теперь тоже неявно перечисляется, и (1..3) как отдельный объект визуализируется более осмысленно (вы не можете визуально отличить его от отправки 1..3 непосредственно в конвейер, т.е. элемент):

1
2
3

Как отформатированы массивы для отображения

Когда команда или выражение не записываются в переменную, не отправляются в конвейер другой команде и не перенаправляются (с > или >>), они неявно выводятся на экран (хост) с использованием вывода PowerShell по умолчанию система форматирования.

Вы можете думать о такой команде, как:

test

эквивалент [1] :

test | Out-Host

Out-Host автоматически выбирает командлет Format-*, который будет использоваться для рендеринга, который подходит для ввода под рукой, на основе первого объекта ввода:Если этот объект имеет 4 или менее свойств, выбирается Format-Table; в противном случае это Format-List.

Однако, если этот первый входной объект является коллекцией (реализует IEnumerable), именно первый элемент этой коллекции основан на выборе командлета форматирования (в отличие от к типу коллекции в целом), и элементы коллекции форматируются индивидуально с помощью этого командлета.

В случае, когда ваша переменная $result получает выходные данные, первым элементом входного массива является экземпляр [pscustomobject] (созданный с помощью New-Object PSObject) со свойством 1, key1; поэтому выбирается Format-Table, а экземпляры [pscustomobject] `, составляющие массив, отображаются в табличном формате.

В отличие от этого, в случае вашего вызова test, первый элемент входного массива - это другой массив , который сам по себе не далее перечисляется. Get-Member -InputObject (1,2) -Type Property показывает, что массив имеет 8 свойств (Count, IsFixedSize, IsReadOnly, IsSynchronized, Length, LongLength, Rank, SyncRoot), поэтому Format-List выбирается, перечисляя каждое свойство как пару имя / значение в отдельной строке.

Конечно, вы можете явно использовать командлет форматирования , и PetSerAl указывает, что командлеты форматирования поддерживают параметр -Expand, который дает вам возможность контролировать форматирование объектов ввода, являющихся коллекциями. : вы можете попросить перечислить коллекцию, т. е. вывести ее элементы (-Expand EnumOnly, которая является значением по умолчанию), чтобы показать только собственные свойства коллекции без печати ее элементов (-Expand CoreOnly) или оба (-Expand Both).

Обратите внимание, однако, что вы не можете запросить дополнительные уровни перечисления через -Expand, поэтому ваш вывод test не может быть напрямую отформатирован для отображения отдельных элементов вашего вложенного массива. Однако это легко сделать, отправив по трубопроводу Write-Output, который выполняет дополнительный уровень перечисления, необходимый для визуализации элементов по отдельности:

test | Write-Output

[1] Точнее, как указывает PetSerAl, это: . { test } 2>&1 | Out-Default, что позволяет пользователям переопределять командлет Out-Default для пользовательского форматирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...