powershell 对象的输出在start-sleep之后出现奇怪的延迟(或者直到脚本结束)

acruukt9  于 2023-08-05  发布在  Shell
关注(0)|答案(3)|浏览(138)

由于某种原因,对象在sleep命令执行完之前不会输出。

[pscustomobject]@{message = 'hi'}; sleep 5

字符串
还有一个例子。在循环结束之前,您不会看到输出。

foreach ($i in 1..60) { 
  if ($i -eq 1) { [pscustomobject]@{message = $i} } 
  sleep 1
}


我猜你必须输出至少2个对象才能看到任何东西?¯_()_/¯ 15秒后,您将看到两个对象。

foreach ($i in 1..60) {
  if ($i -eq 1 -or $i -eq 15) { [pscustomobject]@{message = $i} }
  sleep 1
}


或者输出足够的属性(> 4)来隐式调用format-list而不是format-table。* 格式表是问题。* 这马上出来。

[pscustomobject]@{a=1; b=2; c=3; d=4; e=5}; sleep 10


我想知道是否可以像-NoWait一样添加一个参数到format-table。
格式化文件包含列宽的已知对象类型不存在此问题。

foreach ($i in 1..60) { 
  if ($i -eq 1) { get-process powershell } 
  sleep 1
}


或默认为format-custom的对象:

foreach ($i in 1..60) { 
  if ($i -eq 1) { get-date } 
  sleep 1
}

lnvxswe2

lnvxswe21#

tl;dr

  • 如果命令的输出格式为**Format-Table**-无论是 * 隐式 ,如您的情况*,还是显式-display 输出可以 * 视情况 * 延迟 ,(至少)300毫秒*(请参阅下一节了解原因和时间),这具有以下含义:
  • 如问题中所述,a subsequentStart-Sleep submitted before the delay has elapsed(至少)the duration of sleep.
    Format-Table只能检测300毫秒的延迟是否已经过去 * 如果并且当它重新获得控制权 *,这只有在输入命令 * 发出另一个输出对象 * 或 * 终止 * 时才会发生。*
  • 使用 * 隐式 * 应用的Format-Table,* 后续 * Write-HostOut-Host调用可能会产生意外出现 * 第一个 * 的输出,以及任何针对output stream * 而不是成功输出流的调用,例如调用Write-WarningWrite-Verbose
  • 您可以通过将命令显式地传输到Out-HostFormat-Table(或任何其他Format-* cmdlet)来 * 强制 * 同步 * 显示 * 输出;也就是说,然后保持不同流之间的输出顺序。
  • 但是,这样做意味着只生成 for-display 输出,这意味着您失去了(有意义地)捕获或中继命令输出的能力。
# 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个或更少的属性 (这是自动选择 * 表 * 显示),它等待长达300毫秒。在显示输出之前,努力确定合适的列宽。
如果在该时间段之前使用Start-Sleep
输出将延迟(至少)睡眠时间 *,因为Format-Table不会重新获得控制权,直到它 * 接收到输入命令的下一个输出对象 * 或 * 输入命令终止 *。
但是,发生 * 不 * 触发隐式Format-Table的输出对象不受影响:

# Immediate output, before sleeping ends:

# Out-of-band formatting of a .NET primitive.
1; Start-Sleep 5

# Implicit Format-*List* formatting due to having 5+ properties.
[pscustomobject] @{ a=1; b=2; c=3; d=4; e=5 }; Start-Sleep 10


相比之下,由于命令的输出是一个只有 1 属性的对象,并且其类型([pscustomobject])没有与之关联的预定义格式设置数据,因此它会触发隐式Format-Table设置,因此会出现问题。

简而言之:以下命令输出会受到影响,因为它们选择了隐式Format-Table输出,但缺少预定义的列宽,因此需要延迟:

  • 类型恰好具有 *4个或更少 * 属性**的对象
  • if 这些类型 * 没有 * 关联的预定义格式化数据**(参见about_Format.ps1xml),对于[pscustomobject]示例通常是这样。
  • 此外,但不太常见的是,类型 * 具有 * 格式化数据,* 默认为表视图 *,但没有预定义的列 * 宽度 *,也会受到影响(例如,New-Guid输出的System.Guid类型示例)。
  • 作为一个繁琐的临时替代创作格式化数据,你可以使用Format-Tablecalculated properties来 * 预定义每个显示属性(列)的列宽 *;然而,注意,这再次仅适用于 to-display 输出;例如:
# Produces instant display output, due to predefined column widths.
[pscustomobject] @{ a=1; b=2 } |
  Format-Table -Property @{ Expression='a'; Width = 10}, 
                         @{ Expression='b'; Width = 20} 
Start-Sleep 5


类型 * 没有 * 格式化数据有 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

xkftehaa

xkftehaa2#

将自定义对象通过管道传输到Out-Host cmdlet:

[pscustomobject]@{message = 'hi'} | Out-Host; sleep 5

字符串
使用Out-Hostcmdlet时,会立即向主机显示结果。如果没有它,对象将输出到管道,直到Start-Sleep cmdlet之后才返回管道。

axr492tv

axr492tv3#

输出少于5个属性,并且format-table隐式运行。在显示第一个对象之前,Format-table将等待第二个对象 * 不确定 * 的时间。这适用于没有xml文件的对象类型(如pscustomobject),它们定义了一个 default 表视图。

# no output for 5 seconds

&{get-date
sleep 5
get-date} | format-table

DisplayHint DateTime                               Date                 Day DayOfWeek DayOfYear Hour  Kind Millisecond Minute
----------- --------                               ----                 --- --------- --------- ----  ---- ----------- ------
   DateTime Saturday, February 8, 2020 10:24:48 AM 2/8/2020 12:00:00 AM   8  Saturday        39   10 Local         618     24
   DateTime Saturday, February 8, 2020 10:24:53 AM 2/8/2020 12:00:00 AM   8  Saturday        39   10 Local         892     24

字符串
与format-list比较:

& {get-date
sleep 5
get-date} | format-list 

DisplayHint : DateTime
Date        : 2/8/2020 12:00:00 AM
Day         : 8
DayOfWeek   : Saturday
DayOfYear   : 39
Hour        : 20
Kind        : Local
Millisecond : 408
Minute      : 37
Month       : 2
Second      : 18
Ticks       : 637167910384087860
TimeOfDay   : 20:37:18.4087860
Year        : 2020
DateTime    : Saturday, February 8, 2020 8:37:18 PM

DisplayHint : DateTime
Date        : 2/8/2020 12:00:00 AM
Day         : 8
DayOfWeek   : Saturday
DayOfYear   : 39
Hour        : 20
Kind        : Local
Millisecond : 662
Minute      : 37
Month       : 2
Second      : 23
Ticks       : 637167910436622480
TimeOfDay   : 20:37:23.6622480
Year        : 2020
DateTime    : Saturday, February 8, 2020 8:37:23 PM

相关问题