这是另一个问题的衍生物,它位于这里:Formatting an Object as a neatly looking list我认为论证的基础是错误的,因为我们之后并没有处理对象的格式化。这仅适用于控制台显示的外观,但在操作包含对象的变量时,它可能会影响对象的完整性。
我需要的是创建一个固有输出列表(而不是表)的对象。我知道这是可能的,因为我已经测试了许多我没有写过的函数,而且创建的对象实际上是列表。无需使用Format-List来扭曲或塑造已存在的内容。我只是无法弄清楚为什么有时输出是列表或表。我不确定魔法在哪里。但是我知道当我在运行包含创建对象的变量之前运行$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 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
首先使用列y
和x
建立表格输出格式,但$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执行此操作。如果您的输出是用于进一步处理:首先不要打扰它的格式。将它留给用户如何显示数据。