Невозможно приостановить или спать после выбора объекта

В некоторых случаях, если я пытаюсь сделать паузу или спать после Select-Object команда, пауза / сон происходит перед командой.

Например, с

Get-NetAdapter | Select-Object Name,Status
Pause

или же

Get-NetAdapter | Select-Object Name,Status | Where-Object {$_ -ne $null}
Pause

выход:

Нажмите Enter, чтобы продолжить...:

Название Статус
----     ------
Wi-Fi    Up
Ethernet отключен

Тогда как с

Get-NetAdapter | Select-Object Name,Status | Format-Table
Pause

выход:

Название Статус
----     ------
Wi-Fi    Up
Ethernet отключен

Нажмите Enter, чтобы продолжить...:

Что тут происходит? Это ошибка или особенность?

2 ответа

То, что вы видите, является следствием новой функции PowerShell v5. Format-Table теперь собираем данные за 300 миллисекунд, чтобы найти лучшую ширину столбца. Это работает таким образом, даже если вы явно указываете -AutoSize:$false,

Когда вы вводите команду в командной строке, эта команда неявно передается в один экземпляр 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>

неявный 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>

С этим кодом, конец блока явного 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

разворот это:

Get-Process |Select-Object -Property Name  |%{Write-host $_.name};pause

Здесь снова пауза запускается первой:

Get-Process |%{$_.name | Set-Content 'c:\temp\test.txt';$_} |Select-Object -Property Name  ;pause

Но не здесь

Get-Process |%{$_.name | Set-Content 'c:\temp\test.txt';Start-Sleep -Milliseconds 1;$_} |Select-Object
-Property Name  ;pause

Для меня в PowerShell V5.0 все работает так, как будто хост не нужен в инструкциях, которые передаются по конвейеру, тогда эти инструкции выполняются асинхронно.

Мне бы хотелось, чтобы такие люди, как @Keith Hill, смотрели на это поведение.

Другие вопросы по тегам