tl;dr
# The Out-Host forces instant display, before sleeping starts.
# However, use of Out-Host means you can't capture the output.
[pscustomobject] @{message = 'hi'} | Out-Host; sleep 5
臭名昭著的PSv5+ asynchronous behavior of implicitly applied Format-Table output 解释了这种行为:对于具有4 个或更少属性 的数据类型没有预定义的格式化数据(这是自动选择table 显示),它最多等待 300 毫秒。在显示输出之前,努力确定合适的列宽。
如果您在这段时间过去之前使用Start-Sleep,那么您暂停只要您还在睡觉就一直等待。
发生不触发隐式Format-Table格式的输出对象不受影响,但是:
# Immediate output, before sleeping ends:
# Out-of-band formatting of a .NET primitive.
PS> 1; Start-Sleep 5
# Implicit Format-*List* formatting due to having 5+ properties.
PS> [pscustomobject]@{a=1; b=2; c=3; d=4; e=5}; sleep 10
相比之下,由于您的命令输出是一个只有 1 属性的对象,并且它的类型 ([pscustomobject]) 没有与之关联的预定义格式数据,因此它会触发隐式 Format-Table 格式,因此显示问题。
简而言之:以下命令输出受到影响,因为它们选择隐式 Format-Table 输出,而缺少预定义的列宽,因此需要延迟:
类型没有具有5个或更多属性的格式化数据默认隐式应用Format-List,由于逐行输出,不需要确定有用的列宽,因此没有延迟。
请注意,这只是一个 显示 问题,如果命令被捕获或发送到管道,则数据 会立即输出(尽管命令不会整体完成,直到Start-Sleep 期结束):
# The ForEach-Object command's script block receives the [pscustomobject]
# instance right away (and itself prints it *immediately* to the display,
# due to outputting a *string* (which never triggers the asynchronous behavior).
& { [pscustomobject]@{message = 'hi'}; sleep 5 } | ForEach-Object { "[$_]" }
虽然有多种方法可以强制同步(立即)显示输出,它们都会改变命令的基本行为:
# Piping to Out-Host:
# Directly prints to the *display* (host).
# No way for a caller to capture the result or for processing
# the result in a pipeline.
[pscustomobject]@{message = 'hi'} | Out-Host; sleep 5
# Using Write-Host:
# Prints directly to the *display* (host) by default.
# While it *is* possible to capture the result via output stream 6.
# the information stream (6> file.txt), that output:
# * is invariably converted to *strings*
# * and the string representation does *not* use the friendly default
# output formatting; instead, the objects are stringified with simple
# [psobject.].ToString() calls, which results in a much less friendly
# representation.
Write-Host ([pscustomobject]@{message = 'hi'}); sleep 5
# Piping to a Format-* cmdlet explicitly:
# While this does write to the success-output stream (stream number 1),
# as the command would by default, what is written isn't the original
# objects, but *formatting instructions*, which are useless for further
# programmatic processing.
# However, for redirecting the output to a file with Out-File or >
# this makes no difference, because they convert the formatting instructions
# to the strings you would see on the screen by default.
# By contrast, using Set-Content or any other cmdlet that expects actual data
# would not work meaningfully.
[pscustomobject]@{message = 'hi'} | Format-Table; sleep 5