本文介绍了如果不分配给变量,为什么 Powershell Array of Array 显示不同的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果 cmdlet 返回数组数组,例如:

If a cmdlet returns array of array, for example:

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()
}

那么返回值赋值的时候输出就不一样了.

Then the output is different when the return value is assigned.

如果直接运行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

如果一个 cmdlet 返回一个一级数组,test$(test) 的输出是一样的.

And if a cmdlet returns a one level array, the output of test and $(test) is the same.

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

推荐答案

PetSerAl 提供了一个简洁的关键指针评论:

PetSerAl has provided the crucial pointer in a terse comment:

输出渲染的差异归结为以下事实:

  • 语句 test 是一个 命令(对函数、cmdlet 或外部程序的调用)
  • $result(之前捕获了 test 的输出)是一个 表达式(只涉及变量引用、PowerShell 的运算符和 .NET 方法调用,在管道之外——尽管它可能包含嵌套命令).
  • statement test is a command (a call to a function, cmdlet, or external program)
  • whereas $result (which previously captured test's output) is an expression (something involving only variable references, PowerShell's operators and .NET method calls, outside a pipeline - though it may contain nested commands).

通过从您的 test 函数(函数是命令的一种形式)输出 , $results.ToArray(),您正在使用 ,,数组构造运算符,用于将 $results.ToArray()(生成数组数组)包装在 辅助、临时 单元素数组中,这是确保集合作为单个对象传递而不是枚举其元素的常用技术.

By outputting , $results.ToArray() from your test function (a function is one form of a command), you're using ,, the array-construction operator, to wrap $results.ToArray() (which results in array of arrays) in an auxiliary, transitory single-element array, which is a common technique to ensure that a collection is passed on as a single object rather than having its elements enumerated.

也就是说,辅助.包装器数组是:

  • 总是丢失到管道的输出,由于管道的自动展开(展开)行为,

  • invariably lost on output to the pipeline, due to the pipeline's automatic unwrapping (unrolling) behavior,

但它确保包装的数组被管道中的下一个命令视为单个对象.>

but it ensures that the wrapped array is seen as a single object by the next command in the pipeline.

在您的函数中,概念上更清晰但更冗长的 , $results.ToArray() 等效项是 Write-Output -NoEnumerate $results.ToArray();也就是说,PowerShell 的通常隐式输出是显式的,请求抑制枚举 输出集合的默认行为.

The conceptually clearer, but more verbose equivalent of , $results.ToArray() inside your function is Write-Output -NoEnumerate $results.ToArray(); that is, PowerShell's usually implicit output is made explicit, with a request to suppress the default behavior of enumerating output collections.

鉴于管道中没有其他命令,tests 输出被隐式打印到屏幕.在手头的情况下,将数组数组打印为单个对象会导致您看到的属性列表输出格式.

Given that there is no additional command in the pipeline, tests output is implicitly printed to the screen.In the case at hand, printing an array of arrays as a single object results in the property-list output formatting you saw.

相比之下,$result,由于是一个表达式,被隐式枚举.也就是说,从 test 捕获的数组数组 - 没有辅助.包装阵列!- 一次发送一个元素到输出格式系统,然后这些元素会更有意义地呈现.

By contrast, $result, due to being an expression is implicitly enumerated. That is, the array of arrays captured from test - without the aux. wrapper array! - is sent one element at a time to the output-formatting system, and these elements then render more meaningfully.

提供一个更简单的例子:

假设您的函数 test 使用 return , , (1..3) 输出一个包含 3 元素数组的容器数组,该数组最终包含在一个 aux 中.单元素数组(顺便说一句:PowerShell中的return只是用于退出函数或脚本块的语法糖,它与输出的内容没有直接关系).

Assume your function test uses return , , (1..3) to output a container array containing a 3-element array that is finally wrapped in an aux. single-element array (as an aside: return in PowerShell is just syntactic sugar for exiting a function or script block, it has no direct relationship with what is output).

执行test函数就相当于直接执行下面的表达式:

Executing the test function is then the equivalent of direct execution of the following expression:

, , (1..3)

也就是外,辅助.由于隐式枚举,数组再次被丢弃,并且 , (1..3) 被呈现为一个单个对象,导致属性列表格式:

That is, the outer, aux. array is again discarded due to implicit enumeration and , (1..3) is rendered as a single object, resulting in the property-list format:

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

相比之下,执行 $result(在运行 $result = test 之后)就相当于:

By contrast, executing $result (after running $result = test) is then the equivalent of just:

, (1..3)

也就是外,辅助.数组在 $result = test 期间丢失,容器数组现在也被隐式枚举,并且 (1..3) 作为单个对象呈现更有意义(你可以t 在视觉上区分它与将 1..3 直接发送到管道,即逐个元素):

That is, the outer, aux. array was lost during $result = test, the container array too is now implicitly enumerated, and (1..3) as a single object renders more meaningfully (you can't visually distinguish it from sending 1..3 directly to the pipeline, i.e., element by element):

1
2
3

如何格式化数组以供显示

当命令或表达式既没有在变量中捕获,也没有发送到管道到另一个命令,也没有重定向(使用 >>>>)时,它使用 PowerShell 的默认输出格式系统隐式打印到屏幕(主机).


How arrays are formatted for display

When a command or expression is neither captured in a variable nor sent to the pipeline to another command nor redirected (with > or >>), it is implicitly printed to the screen (host), using PowerShell's default output-formatting system.

你可以想到一个命令,例如:

You can think of a command such as:

test

相当于:

test | Out-Host

Out-Host 根据第一个输入对象自动选择一个 Format-* cmdlet 用于呈现适合手头的输入:如果该对象具有 4 个或更少的属性,则选择 Format-Table;否则为Format-List.

Out-Host automatically chooses a Format-* cmdlet to use for rendering that is suitable for the input at hand, based on the first input object:If that object has 4 or fewer properties, Format-Table is chosen; otherwise, it is Format-List.

然而,如果第一个输入对象是一个集合(实现了IEnumerable),则该集合的第一个元素是格式化的选择cmdlet 基于(而不是作为一个整体的集合类型),并且集合的元素使用该 cmdlet 单独格式化.

However, if that first input object is a collection (implements IEnumerable), it is that collection's first element that the choice of formatting cmdlet is based on (as opposed to the collection type as a whole), and the collection's elements are formatted individually using that cmdlet.

在您的 $result 变量获得输出的情况下,输入数组的第一个元素是一个 [pscustomobject] 实例(使用 New-Object PSObject) 有 1 个属性,key1;因此,选择了 Format-Table,并且组成数组的 [pscustomobject]` 实例以表格格式显示.

In the case of your $result variable getting output, the input array's first element is a [pscustomobject] instance (created with New-Object PSObject) with 1 property, key1; therefore, Format-Table is chosen, and the [pscustomobject]` instances that make up the array are shown in a tabular format.

相比之下,在您的 test 调用的情况下,输入数组的第一个元素是另一个数组,它本身不会进一步枚举.Get-Member -InputObject (1,2) -Type Property 显示一个数组有 8 个属性(CountIsFixedSizeIsReadOnlyIsSynchronizedLengthLongLengthRankSyncRoot),这就是选择 Format-List 的原因,将每个属性作为名称/值对列在自己的行上.

By contrast, in the case of your test call, the input array's first element is another array, which is itself not further enumerated. Get-Member -InputObject (1,2) -Type Property reveals that an array has 8 properties (Count, IsFixedSize, IsReadOnly, IsSynchronized, Length, LongLength, Rank, SyncRoot), which is why Format-List is chosen, listing each property as a name / value pair on its own line.

当然,您可以选择显式使用格式化 cmdlet,并且 PetSerAl 指出格式化 cmdlet 支持 -Expand 参数,这使您可以控制如何作为集合的输入对象被格式化:您可以要求枚举集合,即打印它的元素(-Expand EnumOnly,这是默认值),以显示只是集合自己的属性,而不打印其元素(-Expand CoreOnly),或两者(-Expand Both).

Of course, you can opt to use a formatting cmdlet explicitly, and PetSerAl points out that the formatting cmdlets support the -Expand parameter, which gives you control over how input objects that are collections are formatted: you can ask to have the collection enumerated, i.e., to print its elements (-Expand EnumOnly, which is the default), to show just the collection's own properties, without printing its elements (-Expand CoreOnly), or both (-Expand Both).

但是请注意,您不能通过 -Expand 请求 附加 枚举级别,因此您的 test 输出不能直接格式化以显示嵌套数组的各个元素.但是,通过管道传递到 Write-Output 来实现这一点是微不足道的,它执行单独呈现元素所需的额外枚举级别:

Note, however, that you cannot request additional levels of enumeration via -Expand, so your test output cannot be directly formatted to show the individual elements of your nested array.However, it is trivial to make that happen by piping to Write-Output, which performs the additional level of enumeration required to render the elements individually:

test | Write-Output


这篇关于如果不分配给变量,为什么 Powershell Array of Array 显示不同的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 09:14