如何创建输出List(不是表)的Object

问题描述 投票:2回答:1

这是另一个问题的衍生物,它位于这里:Formatting an Object as a neatly looking list我认为论证的基础是错误的,因为我们之后并没有处理对象的格式化。这仅适用于控制台显示的外观,但在操作包含对象的变量时,它可能会影响对象的完整性。

我需要的是创建一个固有输出列表(而不是表)的对象。我知道这是可能的,因为我已经测试了许多我没有写过的函数,而且创建的对象实际上是列表。无需使用Format-List来扭曲或塑造已存在的内容。我只是无法弄清楚为什么有时输出是列表或表。我不确定魔法在哪里。但是我知道当我在运行包含创建对象的变量之前运行$Host时,我得到了Host生成的对象,这是一个列表,然后将对象整形为一个通常显示为表的列表。当然,这可能会给出我想要的结果,但我不打算显示主机信息。那么解决方案是什么呢,我希望有人可以解释一下。

list powershell object
1个回答
8
投票

PowerShell在向用户显示数据/对象时执行一些默认格式设置。通常,对象在具有最多4个属性时以表格形式显示,而在具有4个以上属性时以列表形式显示。

如果连续输出多个内容,PowerShell会将第一个对象的格式(列表/表)应用于所有后续对象。我不知道这种行为背后的确切原因,但可能是为了使输出更加一致。

示范:

PS C:\> $o1 = New-Object -Type PSObject -Property @{a=1;b=2;c=3;d=4;e=5}
PS C:\> $o2 = New-Object -Type PSObject -Property @{x='foo';y='bar'}
PS C:\> $o1

c : 3
e : 5
d : 4
b : 2
a : 1

PS C:\> $o2

y                                    x
-                                    -
bar                                  foo

PS C:\> $o1; $o2

c : 3
e : 5
d : 4
b : 2
a : 1

y : bar
x : foo

但是,请注意,如果以错误的顺序输出对象,依赖此行为可能会导致意外结果:

PS C:\> $o2; $o1

y                                    x
-                                    -
bar                                  foo         # ← properties of $o2
                                                 # ← empty line for $o1!

$o1在上面的输出中显示为空白行,因为输出$o2首先使用列yx建立表格输出格式,但$o1没有这些属性。缺少的属性在表格输出中显示为空值,而输出中省略了其他属性。在某些情况下,您可能会以列表形式从第二个对象/列表中获取输出(例如,在PowerShell控制台中运行Get-Process; Get-ChildItem)。

您可以通过在Format-Table(或Format-List)cmdlet中管理后续对象或对象数组,将其强制显示为单独的表(或列表):

PS C:\> $o2; $o1 | Format-Table

y                                    x
-                                    -
bar                                  foo


              c            e            d            b            a
              -            -            -            -            -
              3            5            4            2            1

您还可以通过管道(例如)Out-Default强制PowerShell单独显示每个变量:

PS C:\> $o2 | Out-Default; $o1 | Out-Default

y   x
-   -
bar foo

c : 3
e : 5
d : 4
b : 2
a : 1

但请注意,这会写入控制台,因此无法再捕获,重定向或流水线化生成的输出。仅在您想要向用户显示内容时使用此选项。

有关PowerShell输出格式see here的其他信息。


有一些方法可以改变对象显示方式的默认行为,但遗憾的是它们并不简单。首先,您可以定义一个default display property set,让PowerShell显示并非所有属性,而只是一个特定的子集。

PS C:\> $props = 'c', 'd'
PS C:\> $default = New-Object Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$props)
PS C:\> $members = [Management.Automation.PSMemberInfo[]]@($default)
PS C:\> $o1 | Add-Member MemberSet PSStandardMembers $members
PS C:\> $o1

                c                    d
                -                    -
                3                    4

您仍然可以使用Format-List *显示所有属性:

PS C:\> $o1 | Format-List *

c : 3
e : 5
d : 4
b : 2
a : 1

定义默认显示属性集不允许您定义输出格式。要做到这一点,你可能需要写一个自定义formatting file。为此,您可能还需要为对象定义custom type

$formatFile = "$HOME\Documents\WindowsPowerShell\Your.Format.ps1xml"
$typeFile   = "$HOME\Documents\WindowsPowerShell\Your.Type.ps1xml"

@'
<?xml version="1.0" encoding="utf-8" ?>
<Configuration>
  <ViewDefinitions>
    <View>
      <Name>Default</Name>
      <ViewSelectedBy>
        <TypeName>Foo.Bar</TypeName>
      </ViewSelectedBy>
      <ListControl>
        ...
      </ListControl>
    </View>
  </ViewDefinitions>
</Configuration>
'@ | Set-Content $formatFile
Update-FormatData -AppendPath $formatFile

@'
<?xml version="1.0" encoding="utf-8" ?>
<Types>
  <Type>
    <Name>Foo.Bar</Name>
    <Members>
      ...
    </Members>
  </Type>
</Types>
'@ | Set-Content $typeFile
Update-TypeData -AppendPath $typeFile

$o2.PSTypeNames.Insert(0, 'Foo.Bar')

杰弗里希克斯写了一篇你可能想读的article series on the subject


尽管如此,除非你有非常令人信服的理由,否则我不建议走这条路。我之前尝试过解释,但是@TesselatingHeckler比我简洁得多,所以我要引用他的话:

PowerShell不是bash,它具有内容和表示的分离,就像HTML和CSS一样。

您通常要在PowerShell中执行的操作是将数据保存在对象中,并使这些对象的属性包含“原始”(即未格式化)数据。这为您提供了处理数据的最大灵活性。格式化数据通常只会妨碍您,因为它会强制您再次解析/转换数据。仅在需要将数据显示给用户时格式化数据,并使用Format-* cmdlet执行此操作。如果您的输出是用于进一步处理:首先不要打扰它的格式。将它留给用户如何显示数据。

© www.soinside.com 2019 - 2024. All rights reserved.