如何创建输出列表(不是表格)的对象 [英] How to create an Object that outputs a List (Not A Table)

查看:12
本文介绍了如何创建输出列表(不是表格)的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是另一个问题的衍生,位于此处:将对象格式化为整洁的列表我认为,论点的基础是错误的,因为我们之后没有处理对象的格式.这仅适用于控制台显示的外观,但在您操作包含对象的变量时,它可能会影响对象的完整性.

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

解决方案

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: 3: 5d : 4乙:2一:1PS C:> $o2y x- -酒吧富PS C:> $o1;$o2: 3: 5d : 4乙:2一:1y : 酒吧x : 富

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

<前>PS C:> $o2;$o1y x- -bar foo # ←$o2 的性质# ←$o1 的空行!

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

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

<前>PS C:> $o2;$o1 |格式表y x- -酒吧富c d b a- - - - -3 5 4 2 1

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

<前>PS C:> $o2 |违约;$o1 |超出默认y x- -酒吧富: 3: 5d : 4乙:2一:1

但是请注意,这会写入控制台,因此无法再捕获、重定向或流水线化结果输出.仅当您想向用户显示某些内容时才使用它.

有关 PowerShell 输出格式的其他信息 见这里.

<小时>

有多种方法可以更改对象显示方式的默认行为,但不幸的是,它们并不完全简单.一方面,您可以定义一个 默认显示属性设置 让 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 |添加成员 MemberSet PSStandardMembers $membersPS C:> $o1cd- -3 4

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

<前>PS C:> $o1 |格式列表 *: 3: 5d : 4乙:2一:1

虽然定义默认显示属性集不允许您定义输出格式.为此,您可能需要编写一个自定义的格式化文件.为此,您可能还需要定义一个 自定义类型 用于您的对象.

$formatFile = "$HOMEDocumentsWindowsPowerShellYour.Format.ps1xml"$typeFile = "$HOMEDocumentsWindowsPowerShellYour.Type.ps1xml"@'<?xml version="1.0" encoding="utf-8" ?><配置><视图定义><查看><名称>默认</名称><ViewSelectedBy><TypeName>Foo.Bar</TypeName></ViewSelectedBy><列表控件>...</ListControl></查看></视图定义></配置>'@ |设置内容 $formatFile更新格式数据 -AppendPath $formatFile@'<?xml version="1.0" encoding="utf-8" ?><类型><类型><名称>Foo.Bar</名称><会员>...</会员></类型></类型>'@ |设置内容 $typeFile更新类型数据 -AppendPath $typeFile$o2.PSTypeNames.Insert(0, 'Foo.Bar')

Jeffrey Hicks 写了一篇文章 系列 关于您可能想要阅读的主题.

<小时>

综上所述,除非您有非常令人信服的理由,否则我不建议您走这条路.我之前尝试解释过,但是 @TesselatingHeckler 说得比我简明得多,所以我要引用他的话:

<块引用>

PowerShell 不是 bash,它像 HTML 和 CSS 一样将内容和表示分离.

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

This is a spin-off from another question which is located here: Formatting an Object as a neatly looking list The basis of the argument, I believe, was wrong since we're not dealing with formatting of the object afterwards. That's only for looks as shown by the console but it can have bearing on the integrity of the object as you manipulate the variable containing the object.

What I need is to create an object that inherently outputs a list (not a table). I know it's possible because I've tested many functions that I've not written and the objects created are in fact lists. No need to use Format-List to distort or shape what's already there. I just have not being able to figure out why sometimes the output is a list or a table. I'm not sure where the magic is. However I do know that when I run $Host before I run the variable containing the created object I get the object that Host produces, which a list, and that shapes the object afterwards also as a list that normally would be shown as a table. Of course, that may give the result I want but I'm not looking to show the Host information. So what is the solution to this, I wish someone could explain this.

解决方案

PowerShell does some default formatting when it presents data/objects to the user. Usually objects are displayed in tabular form when they have up to 4 properties, and in list form when they have more than 4 properties.

If you output several things in a row, PowerShell applies the format (list/table) from the first object to all subsequent objects. I don't know the exact reasoning behind this behavior, but presumably it's to make the output more consistent.

Demonstration:

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

Beware, however, that relying on this behavior might lead to undesired results if you output objects in the wrong order:

PS C:> $o2; $o1

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

$o1 appears as a blank line in the above output, because outputting $o2 first establishes tabular output format with the columns y and x, but $o1 doesn't have these properties. Missing properties are displayed as blank values in tabular output, whereas additional properties are omitted from the output. There are also cases where you might get the output from the second object/list in list form (run for instance Get-Process; Get-ChildItem in a PowerShell console).

You can force subsequent objects or object arrays to be displayed as separate tables (or lists) by piping them through the Format-Table (or Format-List) cmdlet:

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

y                                    x
-                                    -
bar                                  foo


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

You can also force PowerShell to display each variable individually by piping them through (for instance) Out-Default:

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

y   x
-   -
bar foo

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

Note, however, that this writes to the console, so the resulting output can't be captured, redirected, or pipelined anymore. Use this only if you want to display something to a user.

For additional information about PowerShell output formatting see here.


There are ways to change the default behavior of how an object is displayed, but unfortunately they're not exactly straightforward. For one thing you can define a default display property set to have PowerShell display not all properties, but just a particular subset.

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

You can still get all properties displayed by using Format-List *:

PS C:> $o1 | Format-List *

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

Defining the default display property set doesn't allow you to define the output format though. To do that you probably need to write a custom formatting file. For that to work you probably also need to define a custom type for your objects.

$formatFile = "$HOMEDocumentsWindowsPowerShellYour.Format.ps1xml"
$typeFile   = "$HOMEDocumentsWindowsPowerShellYour.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')

Jeffrey Hicks wrote an article series on the subject that you may want to read.


With all of that said, I would not recommend going this route unless you have very compelling reasons to do so. I tried to explain it before, but @TesselatingHeckler put it much more concisely than me, so I'm going to quote him on this:

PowerShell is not bash, it has a separation of content and presentation, like HTML and CSS have.

What you normally want to do in PowerShell is keep your data in objects, and have the properties of these objects contain the "raw" (i.e. unformatted) data. That gives you the most flexibility for processing your data. Formatted data usually only gets in the way, because it forces you to parse/convert the data again. Format your data only when you need to display it to a user, and use the Format-* cmdlets to do so. And if your output is intended for further processing: don't bother formatting it in the first place. Leave it to the user how he wants to display the data.

这篇关于如何创建输出列表(不是表格)的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆