如果未分配给变量,为什么数组的Powershell数组显示不同的内容

如果未分配给变量,为什么数组的Powershell数组显示不同的内容,powershell,Powershell,如果cmdlet返回数组的数组,例如: function test() { $results = New-Object System.Collections.ArrayList $array = @() for ($idx = 0; $idx -lt 3; $idx++) { $obj = New-Object PSObject -Property @{ "key1" = "value1"; }

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

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
如果cmdlet返回一个一级数组,则
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
} 
测试
的输出:

key1  
----  
value1
value1
value1
在简短的评论中提供了关键的指针:

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

  • 语句
    test
    是一个命令(对函数、cmdlet或外部程序的调用)
  • $result
    (之前捕获了
    测试的输出)是一个表达式(只涉及变量引用、PowerShell运算符和.NET方法调用,在管道外部-尽管它可能包含嵌套命令)
通过从
test
函数(函数是命令的一种形式)输出
,$results.ToArray()
,您使用数组构造运算符
,将
$results.ToArray()
(生成数组数组)包装到辅助的临时单元素数组中,这是确保集合作为单个对象传递而不是枚举其元素的常用技术

也就是说,辅助系统。包装器数组是:

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

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

函数中的
,$results.ToArray()
在概念上更清晰,但更详细的等价物是
写输出-NoEnumerate$results.ToArray()
;也就是说,PowerShell通常隐式的输出是显式的,请求抑制枚举输出集合的默认行为

假定管道中没有其他命令,
tests
输出隐式打印到屏幕上。 在本例中,将数组数组作为单个对象打印会导致您看到的属性列表输出格式

相比之下,
$result
,由于是表达式,因此隐式枚举。也就是说,从
test
-捕获的阵列阵列不带aux。包装器数组!-一次发送一个元素到输出格式系统,然后这些元素呈现得更有意义


要提供一个更简单的示例,请执行以下操作:

假设您的函数
test
使用
return,(1..3)
输出一个容器数组,其中包含一个最终封装在aux中的3元素数组。单元素数组(作为旁白:
return
在PowerShell中只是用于退出函数或脚本块的语法糖,它与输出没有直接关系)

执行
test
函数相当于直接执行以下表达式:

也就是说,外部,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
发送到管道,即逐个元素):


数组的显示格式 如果命令或表达式既没有在变量中捕获,也没有发送到管道到另一个命令,也没有重定向(使用
>
),则使用PowerShell的默认输出格式系统将其隐式打印到屏幕(主机)

您可以考虑以下命令:

test
等同于[1]:

Out Host
根据第一个输入对象,自动选择一个
格式-*
cmdlet用于呈现适合当前输入的内容: 如果该对象具有4个或更少的属性,则选择
格式表
;否则,它是
格式列表

但是,如果第一个输入对象是一个集合(实现
IEnumerable
),则选择格式化cmdlet所基于的是该集合的第一个元素(而不是整个集合类型),并且使用该cmdlet分别格式化集合的元素

$result
变量获得输出的情况下,输入数组的第一个元素是
[pscustomobject]
实例(使用
新对象PSObject
创建),具有1个属性,
键1
;因此,选择了
Format Table
,组成数组的[pscustomobject]`实例以表格格式显示

相反,在
test
调用的情况下,输入数组的第一个元素是另一个数组,它本身没有进一步枚举<代码>获取成员-输入对象(1,2)-类型属性
显示数组有8个属性(
计数
是固定大小
是只读的
是同步的
长度
同步根
),这就是为什么选择了
格式列表
,将每个属性作为名称/值对列在其自己的行中

当然,您可以选择显式使用格式化cmdlet,PetSerAl指出,格式化cmdlet支持
-Expand
参数,这使您可以控制
1
2
3
test
test | Out-Host
test | Write-Output