是什么导致 select-object 的输出被截断?
What causes the output of select-object to be truncated?
我有以下愚蠢的 PowerShell 脚本:
$username = 'rny'
$null = mkdir "c:\Users$username\YYY"
$null = mkdir "c:\Users$username\YYY\TODO"
$null = mkdir "c:\Users$username\YYY\TODO21-12-22_Foo-bar-baz-etc"
$files = "C:\Users$username\one-two-three-four.sql.wxyz",
"C:\Users$username\YYY\TODO21-11_29_abcdefghijklmnop.wxyz",
"C:\Users$username\YYY\TODO21-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\TODO21-12-22_Foo-bar-baz-etc"
rmdir "c:\Users$username\YYY\TODO"
rmdir "c:\Users$username\YYY"
当我执行它时,get-childItem ... | select-object
管道的输出被截断:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\an...
特别注意最后一行。此行为已被记录 elsewhere on SuperUser,可接受的答案是使用 -autoSize
将输出通过管道传输到 format-table
。到目前为止,还不错。
但是,如果我像这样在 $files
数组的赋值中注释第二个文件
$files = "C:\Users$username\one-two-three-four.sql.wxyz",
# "C:\Users$username\YYY\TODO21-11_29_abcdefghijklmnop.wxyz",
"C:\Users$username\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz"
输出不再被截断:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
这让我感到困惑,因为被截断的文件的名称现在完全可见,对此我没有任何解释。
那么,究竟是什么原因导致文件在一种情况下被截断,而在另一种情况下却没有?
这与 Select-Object
本身没有太大关系 - 它更多地与 PowerShell 如何将值转换为字符串表示形式有关,特别是在这种情况下,当它显示未捕获的输出时它是如何做到的控制台上的 cmdlet。
PowerShell (Windows and Core) 有一堆预配置的“视图”,定义了一些 built-in 类型的呈现方式——例如他们是使用 Format-List
还是 Format-Table
,要显示什么属性,在 table 的情况下,显示每列的宽度 - 请参阅 about_Format.ps1xml.
对于其他类型,PowerShell 会尝试动态生成 best-guess。为此,它等待输入中的前 N 个项目到达,以决定要应用的格式规则。我找不到任何明确的文档说明 PowerShell 等待多少项,所以这可能是一个很好的 follow-up 问题 :-)。
显然,您可以通过为 Format-Table
和 Format-List
传递格式化参数来覆盖这些默认值。
在您的情况下,top-level 脚本已收到包含 PSCustomObject
objects 数组的管道输出(即 Select-Object
的输出),并决定显示它们在 table 中有一列用于 FullName
属性.
示例 1
在您的第一个示例中,它查看了前两个 PSCustomObject 项目并决定将 FullName
列设为 54 个字符宽,因为这是 C:\Users\rny\YYY\TODO21-11_29_abcdefghijklmnop.wxyz
的长度,第三个项目被截断为相同 宽度(如果包含 ...
),因为它未包含在列宽的 decision-making 过程中。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\an...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 54 characters
示例 2
在您的第二个示例中,PowerShell 发现前几个 PSCustomObjects 中最长的 FullName 属性 是 C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
,因此使用的列宽为 70。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 70 characters
示例 3
最后,如果您按照@notjustme 在评论中的建议将 -ExpandProperty FullName
添加到 Select-Object
上,您将得到一个 string
值数组而不是 [=18= 数组]s 这就是为什么您可能会看到 PowerShell 应用不同的格式规则 - 例如您没有得到 FullName
header 因为值是字符串而不是 objects 属性,并且它使用 Format-List
而不是 Format-Table
.
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
为 添加一些背景:
具体来说,您看到的是臭名昭著的 300 毫秒的 效果。 Format-Table
格式化 中内置的延迟,PowerShell 隐含地 适用于具有 4 个或更少属性且没有关联的显式格式化数据的 .NET 类型的实例他们。
有关详细信息,请参阅 (在 同一问题的不同症状 的上下文中给出,即意外输出 排序),但简而言之:延迟用于根据延迟期间收到的特定 属性 值推断 合适的列宽 .
这意味着 具有 属性 值的对象在 300 毫秒后收到。如果它们的值碰巧 宽 比在[=]期间收到的值中最宽的值延迟时间.
具体来说,你的症状意味着只有 前两个 对象在延迟期内被接收,并且两个 属性 值中较长的值随后被锁定在列宽;当稍后收到 third 对象时,列宽已被锁定,并且较长的值被截断(在 Windows PowerShell 中用尾随 ...
表示(3 .
个字符。) 和 …
在 PowerShell (Core) 7+(单个字符))
避免截断的唯一方法是知道最大值。列宽提前 并将其传递给 显式 Format-Table
调用 -
值得注意的是,这会阻止使用输出 作为数据 。 见下文。
这里有一个引发问题的简单方法:
注意:下面的 Select-Object
调用并不是严格需要的,但为了与问题对称而提供。
# Create blocks of two objects with strings of different length in their
# .Prop value: 10 chars. vs. 100 chars.
$count = 10000 # How often to repeat each object in a row.
$objs =
(, [pscustomobject] @{ Prop = ('x' * 10) } * $count) +
(, [pscustomobject] @{ Prop = ('y' * 100) } * $count)
# Depending on the value of $count - which translates into how
# long it takes until the second block of objects starts emitting -
# truncation will occur or not.
$objs | Select-Object Prop
对于 10,000
个对象的块,我确实看到了截断:第一个块需要足够长的时间 - 具有较短的 属性 值 - 以锁定显示列的宽度,导致第二个块中的对象被截断:
Prop
----
xxxxxxxxxx
...
yyyyyyyyy… # <- truncated, because width 10 was locked in during the delay
...
要防止截断,将 calculated property 传递给 Format-Table
以指定最大值。宽度:
$objs | Select-Object Prop | Format-Table @{ n='Prop'; e='Prop'; width = 100 }
我有以下愚蠢的 PowerShell 脚本:
$username = 'rny'
$null = mkdir "c:\Users$username\YYY"
$null = mkdir "c:\Users$username\YYY\TODO"
$null = mkdir "c:\Users$username\YYY\TODO21-12-22_Foo-bar-baz-etc"
$files = "C:\Users$username\one-two-three-four.sql.wxyz",
"C:\Users$username\YYY\TODO21-11_29_abcdefghijklmnop.wxyz",
"C:\Users$username\YYY\TODO21-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\TODO21-12-22_Foo-bar-baz-etc"
rmdir "c:\Users$username\YYY\TODO"
rmdir "c:\Users$username\YYY"
当我执行它时,get-childItem ... | select-object
管道的输出被截断:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\an...
特别注意最后一行。此行为已被记录 elsewhere on SuperUser,可接受的答案是使用 -autoSize
将输出通过管道传输到 format-table
。到目前为止,还不错。
但是,如果我像这样在 $files
数组的赋值中注释第二个文件
$files = "C:\Users$username\one-two-three-four.sql.wxyz",
# "C:\Users$username\YYY\TODO21-11_29_abcdefghijklmnop.wxyz",
"C:\Users$username\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz"
输出不再被截断:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
这让我感到困惑,因为被截断的文件的名称现在完全可见,对此我没有任何解释。
那么,究竟是什么原因导致文件在一种情况下被截断,而在另一种情况下却没有?
这与 Select-Object
本身没有太大关系 - 它更多地与 PowerShell 如何将值转换为字符串表示形式有关,特别是在这种情况下,当它显示未捕获的输出时它是如何做到的控制台上的 cmdlet。
PowerShell (Windows and Core) 有一堆预配置的“视图”,定义了一些 built-in 类型的呈现方式——例如他们是使用 Format-List
还是 Format-Table
,要显示什么属性,在 table 的情况下,显示每列的宽度 - 请参阅 about_Format.ps1xml.
对于其他类型,PowerShell 会尝试动态生成 best-guess。为此,它等待输入中的前 N 个项目到达,以决定要应用的格式规则。我找不到任何明确的文档说明 PowerShell 等待多少项,所以这可能是一个很好的 follow-up 问题 :-)。
显然,您可以通过为 Format-Table
和 Format-List
传递格式化参数来覆盖这些默认值。
在您的情况下,top-level 脚本已收到包含 PSCustomObject
objects 数组的管道输出(即 Select-Object
的输出),并决定显示它们在 table 中有一列用于 FullName
属性.
示例 1
在您的第一个示例中,它查看了前两个 PSCustomObject 项目并决定将 FullName
列设为 54 个字符宽,因为这是 C:\Users\rny\YYY\TODO21-11_29_abcdefghijklmnop.wxyz
的长度,第三个项目被截断为相同 宽度(如果包含 ...
),因为它未包含在列宽的 decision-making 过程中。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\an...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 54 characters
示例 2
在您的第二个示例中,PowerShell 发现前几个 PSCustomObjects 中最长的 FullName 属性 是 C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
,因此使用的列宽为 70。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 70 characters
示例 3
最后,如果您按照@notjustme 在评论中的建议将 -ExpandProperty FullName
添加到 Select-Object
上,您将得到一个 string
值数组而不是 [=18= 数组]s 这就是为什么您可能会看到 PowerShell 应用不同的格式规则 - 例如您没有得到 FullName
header 因为值是字符串而不是 objects 属性,并且它使用 Format-List
而不是 Format-Table
.
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO21-12-22_Foo-bar-baz-etc\another-filename.wxyz
为
具体来说,您看到的是臭名昭著的 300 毫秒的 效果。 Format-Table
格式化 中内置的延迟,PowerShell 隐含地 适用于具有 4 个或更少属性且没有关联的显式格式化数据的 .NET 类型的实例他们。
有关详细信息,请参阅
这意味着 具有 属性 值的对象在 300 毫秒后收到。如果它们的值碰巧 宽 比在[=]期间收到的值中最宽的值延迟时间.
具体来说,你的症状意味着只有 前两个 对象在延迟期内被接收,并且两个 属性 值中较长的值随后被锁定在列宽;当稍后收到 third 对象时,列宽已被锁定,并且较长的值被截断(在 Windows PowerShell 中用尾随 ...
表示(3 .
个字符。) 和 …
在 PowerShell (Core) 7+(单个字符))
避免截断的唯一方法是知道最大值。列宽提前 并将其传递给 显式 Format-Table
调用 -
值得注意的是,这会阻止使用输出 作为数据 。 见下文。
这里有一个引发问题的简单方法:
注意:下面的 Select-Object
调用并不是严格需要的,但为了与问题对称而提供。
# Create blocks of two objects with strings of different length in their
# .Prop value: 10 chars. vs. 100 chars.
$count = 10000 # How often to repeat each object in a row.
$objs =
(, [pscustomobject] @{ Prop = ('x' * 10) } * $count) +
(, [pscustomobject] @{ Prop = ('y' * 100) } * $count)
# Depending on the value of $count - which translates into how
# long it takes until the second block of objects starts emitting -
# truncation will occur or not.
$objs | Select-Object Prop
对于 10,000
个对象的块,我确实看到了截断:第一个块需要足够长的时间 - 具有较短的 属性 值 - 以锁定显示列的宽度,导致第二个块中的对象被截断:
Prop
----
xxxxxxxxxx
...
yyyyyyyyy… # <- truncated, because width 10 was locked in during the delay
...
要防止截断,将 calculated property 传递给 Format-Table
以指定最大值。宽度:
$objs | Select-Object Prop | Format-Table @{ n='Prop'; e='Prop'; width = 100 }