Какой лучший (более чистый) способ игнорировать вывод в PowerShell?
Скажем, у вас есть метод или CMDlet, который что-то возвращает, но вы не хотите его использовать, и вы не хотите его выводить. Я нашел эти два пути:
Add-Item > $null
[void]Add-Item
Add-Item | Out-Null
Что вы используете? Какой подход лучше/чище? Почему?
Ответы
Ответ 1
Я просто сделал несколько тестов из четырех вариантов, о которых я знаю.
Measure-Command {$(1..1000) | Out-Null}
TotalMilliseconds : 76.211
Measure-Command {[Void]$(1..1000)}
TotalMilliseconds : 0.217
Measure-Command {$(1..1000) > $null}
TotalMilliseconds : 0.2478
Measure-Command {$null = $(1..1000)}
TotalMilliseconds : 0.2122
## Control, times vary from 0.21 to 0.24
Measure-Command {$(1..1000)}
TotalMilliseconds : 0.2141
Поэтому я предлагаю вам использовать что-либо, кроме Out-Null
из-за накладных расходов. Следующая важная вещь, для меня, была бы читабельностью. Я вроде как перенаправляюсь на $null
и сам устанавливаю значение $null
. Я предпочитаю кастинг [Void]
, но это может быть не так понятно при взгляде на код или на новых пользователей.
Думаю, я предпочитаю перенаправить вывод на $null
.
Do-Something > $null
Edit
После повторного комментария stej я решил провести еще несколько тестов с конвейерами, чтобы лучше изолировать накладные расходы на выгрузку вывода.
Вот несколько тестов с простым коннектором объектов 1000.
## Control Pipeline
Measure-Command {$(1..1000) | ?{$_ -is [int]}}
TotalMilliseconds : 119.3823
## Out-Null
Measure-Command {$(1..1000) | ?{$_ -is [int]} | Out-Null}
TotalMilliseconds : 190.2193
## Redirect to $null
Measure-Command {$(1..1000) | ?{$_ -is [int]} > $null}
TotalMilliseconds : 119.7923
В этом случае Out-Null
имеет около 60% служебных данных и > $null
имеет около 0,3% служебных данных.
Добавление 2017-10-16: Первоначально я забыл другую опцию с Out-Null
, используя параметр -inputObject
. Используя это, служебные данные, кажется, исчезают, однако синтаксис отличается:
Out-Null -inputObject ($(1..1000) | ?{$_ -is [int]})
И теперь для некоторых тестов с простым конвейером объектов 100.
## Control Pipeline
Measure-Command {$(1..100) | ?{$_ -is [int]}}
TotalMilliseconds : 12.3566
## Out-Null
Measure-Command {$(1..100) | ?{$_ -is [int]} | Out-Null}
TotalMilliseconds : 19.7357
## Redirect to $null
Measure-Command {$(1..1000) | ?{$_ -is [int]} > $null}
TotalMilliseconds : 12.8527
Здесь снова Out-Null
имеет около 60% накладных расходов. В то время как > $null
имеет накладные расходы около 4%. Числа здесь немного отличались от теста к тесту (я побежал каждый примерно 5 раз и выбрал среднюю землю). Но я думаю, что это показывает ясную причину не использовать Out-Null
.
Ответ 2
Существует также командлет Out-Null
, который можно использовать в конвейере, например Add-Item | Out-Null
.
Страница руководства для Out-Null
NAME
Out-Null
SYNOPSIS
Deletes output instead of sending it to the console.
SYNTAX
Out-Null [-inputObject <psobject>] [<CommonParameters>]
DETAILED DESCRIPTION
The Out-Null cmdlet sends output to NULL, in effect, deleting it.
RELATED LINKS
Out-Printer
Out-Host
Out-File
Out-String
Out-Default
REMARKS
For more information, type: "get-help Out-Null -detailed".
For technical information, type: "get-help Out-Null -full".
Ответ 3
Я бы подумал использовать что-то вроде:
function GetList
{
. {
$a = new-object Collections.ArrayList
$a.Add(5)
$a.Add('next 5')
} | Out-Null
$a
}
$x = GetList
Выход из $a.Add
не возвращается - это выполняется для всех вызовов метода $a.Add
. В противном случае вам нужно будет добавить [void]
перед каждым вызовом.
В простых случаях я бы пошел с [void]$a.Add
, потому что совершенно ясно, что вывод не будет использоваться и отбрасывается.
Ответ 4
Я понимаю, что это старый поток, но для тех, кто принимает @JasonMArcher, принятый ответ выше как факт, я удивлен, что он не был исправлен, многие из нас уже давно знают, что на самом деле PIPELINE добавляет задержку и НИЧЕГО делайте это с помощью Out-Null или нет. На самом деле, если вы выполните тесты ниже, вы быстро увидите, что те же самые "более быстрые" кастинга на [void] и $void =, что в течение многих лет мы все использовали мышление, что это было быстрее, на самом деле JUST AS SLOW и на самом деле ОЧЕНЬ МЕДЛЕННО, вы добавляете ЛЮБОЙ конвейерный процесс. Другими словами, как только вы подключаетесь к чему-либо, все правило не использовать out-null переходит в корзину.
Доказательство. Последние 3 теста в списке ниже. Ужасный Out-null был 32339,3792 миллисекунды, но подождите - насколько быстрее было кастинг на [void]? 34121,9251 мс?!? WTF? Это REAL #s на моей системе, приведение к VOID было фактически SLOWER. Как насчет = $null? 34217.685ms..... все еще фригин SLOWER! Итак, как показывают последние три простых теста, Out-Null на самом деле FASTER во многих случаях, когда конвейер уже используется.
Итак, почему это? Просто. Это и всегда было на 100% галлюцинацией, что трубопровод к Out-Null был медленнее. Тем не менее, ТРУБОПРОВОД НА НИЧЕГО медленнее, и разве мы уже не знаем, что с помощью базовой логики? Мы просто не можем знать, КАК МНОГО медленнее, но эти тесты наверняка расскажут о расходах на использование конвейера, если вы можете избежать этого. И мы не были на самом деле на 100% неправильны, потому что существует очень малое количество истинных сценариев, где исключение - пустое зло. Когда? При добавлении Out-Null добавляется ТОЛЬКО работа с конвейером. Другими словами... причина простой команды вроде $(1..1000) | Out-Null, как показано выше, показал истинное значение.
Если вы просто добавляете дополнительный канал в Out-String для каждого теста выше, #s радикально меняются (или просто вставляют те, что указаны ниже), и, как вы можете убедиться сами, Out-Null фактически становится FASTER во многих случаях
$GetProcess = Get-Process
# Batch 1 - Test 1
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$GetProcess | Out-Null
}
}).TotalMilliseconds
# Batch 1 - Test 2
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
[void]($GetProcess)
}
}).TotalMilliseconds
# Batch 1 - Test 3
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$null = $GetProcess
}
}).TotalMilliseconds
# Batch 2 - Test 1
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$GetProcess | Select-Object -Property ProcessName | Out-Null
}
}).TotalMilliseconds
# Batch 2 - Test 2
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
[void]($GetProcess | Select-Object -Property ProcessName )
}
}).TotalMilliseconds
# Batch 2 - Test 3
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$null = $GetProcess | Select-Object -Property ProcessName
}
}).TotalMilliseconds
# Batch 3 - Test 1
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$GetProcess | Select-Object -Property Handles, NPM, PM, WS, VM, CPU, Id, SI, Name | Out-Null
}
}).TotalMilliseconds
# Batch 3 - Test 2
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
[void]($GetProcess | Select-Object -Property Handles, NPM, PM, WS, VM, CPU, Id, SI, Name )
}
}).TotalMilliseconds
# Batch 3 - Test 3
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$null = $GetProcess | Select-Object -Property Handles, NPM, PM, WS, VM, CPU, Id, SI, Name
}
}).TotalMilliseconds
# Batch 4 - Test 1
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$GetProcess | Out-String | Out-Null
}
}).TotalMilliseconds
# Batch 4 - Test 2
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
[void]($GetProcess | Out-String )
}
}).TotalMilliseconds
# Batch 4 - Test 3
(Measure-Command {
for ($i = 1; $i -lt 99; $i++)
{
$null = $GetProcess | Out-String
}
}).TotalMilliseconds