在某些情况下,如果我尝试在Select-Object命令后暂停或休眠,则在命令之前发生暂停/休眠.
例如,用
Get-NetAdapter | Select-Object Name,Status
Pause
Run Code Online (Sandbox Code Playgroud)
要么
Get-NetAdapter | Select-Object Name,Status | Where-Object {$_ -ne $null}
Pause
Run Code Online (Sandbox Code Playgroud)
输出是:
Press Enter to continue...: Name Status ---- ------ Wi-Fi Up Ethernet Disconnected
而与
Get-NetAdapter | Select-Object Name,Status | Format-Table
Pause
Run Code Online (Sandbox Code Playgroud)
输出是:
Name Status ---- ------ Wi-Fi Up Ethernet Disconnected Press Enter to continue...:
这里发生了什么?这是一个错误还是一个功能?
您看到的是新PowerShell v5功能的后果.Format-Table现在收集输入300毫秒,以找到更好的列宽.即使您明确指定,它也会以这种方式工作-AutoSize:$false.
在命令提示符下键入command时,该命令隐式地通过管道传递给单个Out-Default命令实例.Out-Default然后,该命令决定如何格式化对象并在PowerShell主机(控制台)上打印它们.因此,即使您没有Format-Table直接在您的代码中使用,这并不意味着您没有Format-Table在您的管道中.Out-Default可以决定将对象格式化为表格并在Format-Table内部使用.
具有四个或更少属性且没有在格式文件中为它们定义自定义格式的自定义对象被格式化为表格.通过使用Select-Object两个属性,您可以精确地生成该对象.
PowerShell管道是单线程的.这意味着Format-Table当300毫秒间隔过去时,不能只输出所有收集的对象.Format-Table必须等到你管道下一个项目(调用进程块)或报告管道结束(调用结束块).
PS> Get-NetAdapter | Select-Object Name,Status
>>> Pause
>>> [PSCustomObject]@{Name='Some long name';Status='Some long status'} #1
>>> Pause
>>> [PSCustomObject]@{Name='Even longer name';Status='Even longer status'}
>>> Pause
Press Enter to continue...:
Name Status
---- ------
Ethernet Up
Some long name Some long status
Press Enter to continue...:
Even longer... Even longer s...
Press Enter to continue...:
PS>
Run Code Online (Sandbox Code Playgroud)
隐式Format-Table不首先打印任何东西(严格说它打印空行),Pause因为它仍然在等待更多的输入对象(300毫秒尚未过去)来决定列宽.当第一个对象(#1)在300毫秒间隔后出现(假设您不要在按下时禁用Enter),然后Format-Table决定列宽并打印所有收集的对象.将立即打印任何其他对象,但它们不再影响列宽.如果列的值很大,则会被截断.
PS> Get-NetAdapter | Select-Object Name,Status | Format-Table
>>> Pause
Name Status
---- ------
Ethernet Up
Press Enter to continue...:
PS>
Run Code Online (Sandbox Code Playgroud)
使用此代码,Format-Table将在之前执行显式结束块Pause.在结束块中,Format-Table知道它已经获得了所有输入,因此它可以决定列宽并立即输出所有收集的对象.隐式Out-Default看到从Format-Table输出格式化对象,并Out-Default知道它们不需要任何添加格式并立即在主机(控制台)上打印它们.所以在Pause调用之前打印整个表.
注意表格标记结尾的位置差异(两个空行).在第一个例子中,它放在最后Pause.这是因为隐式Format-Table仍处于活动状态并仍在等待,您将其他对象传递给它.只有当您的命令完全完成时,Format-Table才会确认表标记的输入和输出结束.在第二个例子中,显式Format-Table完成之前Pause,所以在Pause命令之前打印整个表(包括表标记的结尾).
表格标记结尾的位置差异也可以在PowerShell的早期版本中注意到.
Format-Table与此无关,我只是在 PowerSell V 4.0 和 PowerShel V5.0 中尝试以下操作,并且可以重现该问题:
Get-Process |Select-Object -Property name ; pause
Run Code Online (Sandbox Code Playgroud)
一个回合是:
Get-Process |Select-Object -Property Name |%{Write-host $_.name};pause
Run Code Online (Sandbox Code Playgroud)
这里再次先运行暂停:
Get-Process |%{$_.name | Set-Content 'c:\temp\test.txt';$_} |Select-Object -Property Name ;pause
Run Code Online (Sandbox Code Playgroud)
但不在这里
Get-Process |%{$_.name | Set-Content 'c:\temp\test.txt';Start-Sleep -Milliseconds 1;$_} |Select-Object
-Property Name ;pause
Run Code Online (Sandbox Code Playgroud)
对我来说,在 PowerShell V5.0 中,一切都正常工作,就像如果流水线指令中不需要主机,那么这些指令就会异步运行。
我希望像@Keith Hill 这样的人能够关注这种行为。
| 归档时间: |
|
| 查看次数: |
845 次 |
| 最近记录: |