Какой лучший (более чистый) способ игнорировать вывод в 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