我有以下愚蠢的 PowerShell 脚本:
$username = 'rny'
$null = mkdir "c:\Users\$username\YYY"
$null = mkdir "c:\Users\$username\YYY\TODO"
$null = mkdir "c:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc"
$files = "C:\Users\$username\one-two-three-four.sql.wxyz",
"C:\Users\$username\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz",
"C:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz"
foreach ($file in $files) {
$null = new-item $file
}
Get-ChildItem . -errorAction silentlyContinue -recurse -filter *.wxyz | select-object fullName
foreach ($file in $files) {
remove-item -literalPath $file
}
rmdir "c:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc"
rmdir "c:\Users\$username\YYY\TODO"
rmdir "c:\Users\$username\YYY"
Run Code Online (Sandbox Code Playgroud)
当我执行它时,管道的输出get-childItem ... | select-object被截断:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\an...
Run Code Online (Sandbox Code Playgroud)
特别注意最后一行。此行为已在 SuperUser 的其他地方注意到,可接受的答案是将输出通过管道传输到format-tablewith -autoSize。到目前为止,一切都很好。
$files但是,如果我像这样评论数组分配中的第二个文件
$files = "C:\Users\$username\one-two-three-four.sql.wxyz",
# "C:\Users\$username\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz",
"C:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz"
Run Code Online (Sandbox Code Playgroud)
输出不再被截断:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz
Run Code Online (Sandbox Code Playgroud)
这让我很困惑,因为被截断的文件的名称现在完全可见,我对此没有任何解释。
那么,究竟是什么导致文件在一种情况下被截断,而在另一种情况下却没有被截断呢?
这与以下问题没有太大关系Select-Object,更多的是与 PowerShell 如何将值转换为字符串表示形式有关,特别是在本例中,当它在控制台上显示来自 cmdlet 的未捕获的输出时,它是如何执行此操作的。
PowerShell(Windows和Core)有一堆预配置的“视图”,它们定义了一些内置类型的呈现方式 - 例如,它们是否使用Format-List或Format-Table,要显示哪些属性,以及在表格的情况下,显示每列的宽度 -请参阅about_Format.ps1xml。
对于其他类型,PowerShell 会尝试即时做出最佳猜测。为此,它会等待输入中的前 N 个项目到达,以决定要应用的格式规则。我找不到任何明确的文档说明 PowerShell 等待多少项,因此这可能是一个很好的后续问题:-)。
显然,您可以通过传递Format-Table和 的格式化参数来覆盖这些默认值Format-List。
在您的情况下,顶级脚本已收到包含PSCustomObject对象数组的管道输出(即 的输出Select-Object),并决定将它们显示在带有属性列的表中FullName。
实施例1
在您的第一个示例中,它查看了前两个 PSCustomObject 项目,并决定将FullName列设置为 54 个字符宽,因为这是 的长度C:\Users\rny\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz,而第三个项目被截断为相同的宽度(如果包含...),因为它未包含在内在列宽的决策过程中。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\an...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 54 characters
Run Code Online (Sandbox Code Playgroud)
实施例2
在第二个示例中,PowerShell 发现前几个 PSCustomObjects 中最长的 FullName 属性是C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz,因此使用列宽 70。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 70 characters
Run Code Online (Sandbox Code Playgroud)
实施例3
最后,如果您执行 @notjustme 在注释中建议的操作并添加-ExpandProperty FullName到Select-Object您得到的值数组string而不是 s 数组PSCustomObject,这就是为什么您可能会看到 PowerShell 应用不同的格式规则 - 例如,您不会获得标FullName头,因为值是字符串而不是具有属性的对象,并且它使用Format-List而不是Format-Table.
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz
Run Code Online (Sandbox Code Playgroud)
为mcclayton 的有用答案添加一些背景添加一些背景:
\n具体来说,您将看到臭名昭著的 300 毫秒的影响。延迟内置于Format-Table格式化中,PowerShell隐式地应用于具有 4 个或更少属性且没有与其关联的显式格式化数据的 .NET 类型实例。
有关详细信息,请参阅此答案(这是在同一问题的不同症状的上下文中给出的,即意外的输出排序),但其不足之处是:延迟用于从收到的特定属性值中推断出合适的列宽度延迟期。
\n这意味着在300 毫秒后接收到具有属性值的对象。如果它们的值恰好比延迟期间收到的值中最宽的值宽,则延迟可能会在其列显示中被截断。
\n具体来说,您的症状意味着在延迟期内仅接收到前两个对象,并且两个属性值中较长的一个随后锁定在列宽中;当稍后收到第三个对象时,列宽已被锁定,并且较长的值被截断(...在 Windows PowerShell(3 个.字符)和\xe2\x80\xa6PowerShell (Core) 7+(单字符)中用尾随表示)
避免截断的唯一方法是知道最大值。提前列宽并将其传递给显式 Format-Table调用 -
\n值得注意的是,这可以防止将输出用作data。见下文。
这是引发问题的简单方法:
\n注意:Select-Object下面的调用并不是严格需要的,而是为了与问题对称而提供的。
# Create blocks of two objects with strings of different length in their \n# .Prop value: 10 chars. vs. 100 chars.\n$count = 10000 # How often to repeat each object in a row.\n$objs = \n (, [pscustomobject] @{ Prop = (\'x\' * 10) } * $count) + \n (, [pscustomobject] @{ Prop = (\'y\' * 100) } * $count)\n\n# Depending on the value of $count - which translates into how\n# long it takes until the second block of objects starts emitting -\n# truncation will occur or not.\n$objs | Select-Object Prop\nRun Code Online (Sandbox Code Playgroud)\n对于对象块10,000,我确实看到了截断:第一个块(具有短属性值)需要足够长的时间才能锁定显示列的宽度,从而导致第二个块中的对象被截断:
Prop\n----\nxxxxxxxxxx\n...\nyyyyyyyyy\xe2\x80\xa6 # <- truncated, because width 10 was locked in during the delay\n...\nRun Code Online (Sandbox Code Playgroud)\n为了防止截断,请传递一个计算属性来Format-Table指定最大值。宽度:
$objs | Select-Object Prop | Format-Table @{ n=\'Prop\'; e=\'Prop\'; width = 100 }\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
4496 次 |
| 最近记录: |