Какой лучший (более чистый) способ игнорировать вывод в PowerShell?

Допустим, у вас есть метод или командлет, который что-то возвращает, но вы не хотите его использовать и не хотите выводить. Я нашел два пути:

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

Что ты используешь? Какой подход лучше / чище? Почему?


person Hinek    schedule 10.03.2011    source источник


Ответы (5)


Я только что провел несколько тестов четырех известных мне вариантов.

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

Изменить

После очередного комментария Стей я решил провести еще несколько тестов с конвейерами, чтобы лучше изолировать накладные расходы, связанные с удалением вывода.

Вот несколько тестов с простым конвейером из 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.

person JasonMArcher    schedule 10.03.2011
comment
Я обычно использую VOID для вещей, которые являются частью языковой строки, и out-null, если это уже большой длинный конвейер. - person klumsy; 10.03.2011
comment
Out-Null, возможно, накладные расходы. Но ... если передать один объект в Out-Null 0,076 миллисекунды, имхо, это все равно отлично подходит для языка сценариев :) - person stej; 11.03.2011
comment
Я немного возился с этим, и я получил лучшую производительность по [void] и ›$ null, используя Out-Null -InputObject ($ (1..1000) |? {$ _ -Is [int]}). - person tomohulk; 06.04.2017
comment
Хороший момент, похоже, что накладных расходов нет. - person JasonMArcher; 17.10.2017
comment
Хотя всегда полезно иметь тесты для сравнения различных способов достижения чего-либо, давайте не будем упускать из виду другой вывод, который можно сделать здесь: если вам не нужно отбрасывать значения сотни тысяч раз, различия в производительности незначительны. И если миллисекунда здесь или там действительно имеет для вас значение, вам, вероятно, вообще не следует использовать PowerShell. Без каких-либо суждений о ранжировании опций в этом отношении, не обязательно жертвовать скоростью ради других качеств, таких как удобочитаемость и выражение намерений программиста. - person Lance U. Matthews; 05.08.2018
comment
Кроме того, лучше (с точки зрения производительности), чем Out-Null, _2 _... т.е. function Out-Void{} - person JohnLBevan; 10.08.2019
comment
Кто-то может также переопределить поведение _1 _..., у которого есть свои плюсы и минусы; хотя в основном последнее. function Out-Null {Param([Parameter(ValueFromPipeline)]$InputObject)Process{$InputObject}}; 1..10 | Out-Null - person JohnLBevan; 10.08.2019
comment
На самом деле с появлением PowerShell Core Out-Null только немного медленнее, чем > $null, примерно в 2 раза медленнее, и я думаю, что это приемлемо. - person CXuesong; 11.08.2019
comment
Если кто-то хочет легко проверить это на своем собственном компьютере, вот функция для этого: function TestSpeed($count) { Measure-Command {$(1..$count) | Out-Null} Measure-Command {[Void]$(1..$count)} Measure-Command {$(1..$count) > $null} Measure-Command {$null = $(1..$count)} } Затем вы можете проверить результат с помощью TestSpeed 50000 | Select-Object -ExpandProperty TotalMilliseconds или любого другого числа, которое вы хотите для своей машины. Вы также получите другую производительность, заключив первую команду в круглые скобки. - person Shenk; 15.08.2019
comment
Важная проблема читабельности - где искать. $ null = сначала выглядит немного странно, но он объявлен в самом начале строки, где вы можете легко его увидеть. Также хорошо знать, что это не дорого, так что спасибо. - person Nick Westgate; 20.04.2021

Я понимаю, что это старый поток, но для тех, кто принимает принятый ответ @JasonMArcher выше как факт, я удивлен, что он не был исправлен, многие из нас знали в течение многих лет, что на самом деле ТРУБОПРОВОД добавляет задержку и НИЧЕГО не связано с тем, это Out-Null или нет. Фактически, если вы запустите приведенные ниже тесты, вы быстро увидите, что те же самые «более быстрые» преобразования в [void] и $ void =, которые мы все годами использовали, думая, что это было быстрее, на самом деле ПРОСТО КАК МЕДЛЕННО и на самом деле ОЧЕНЬ МЕДЛЕННО, когда вы добавляете ЛЮБУЮ конвейерную обработку вообще. Другими словами, как только вы перейдете к чему-либо, все правило отказа от использования out-null отправляется в корзину.

Доказательство, последние 3 теста в списке ниже. Ужасный Out-null был 32339,3792 миллисекунды, но подождите - насколько быстрее было приведение к [void]? 34121.9251 мс?!? Какого черта? Это НАСТОЯЩИЕ # в моей системе, преобразование в VOID было на самом деле МЕДЛЕННЫМ. Как насчет = $ null? 34217,685 мс ..... все еще чертовски МЕДЛЕЕ! Итак, как показывают последние три простых теста, Out-Null на самом деле БЫСТРЕЕ во многих случаях, когда конвейер уже используется.

Итак, почему это? Простой. Это было и всегда было 100% галлюцинацией, что переход к Out-Null был медленнее. Однако работа по ТРУБОПРОВОДУ К чему-либо происходит медленнее, и разве мы не знали об этом с помощью базовой логики? Возможно, мы просто не знали НАМНОГО медленнее, но эти тесты наверняка расскажут о стоимости использования конвейера, если вы можете этого избежать. И мы не ошибались на 100%, потому что существует очень МАЛЕНЬКОЕ количество истинных сценариев, в которых out-null является злом. Когда? При добавлении Out-Null добавляется ТОЛЬКО действие конвейера. Другими словами .... причина в простой команде типа $ (1..1000) | Out-Null, как показано выше, показал истину.

Если вы просто добавите дополнительный канал к Out-String к каждому тесту выше, #s радикально изменятся (или просто вставите те, которые ниже), и, как вы сами можете видеть, Out-Null во многих случаях фактически становится БЫСТРЕЕ:

$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
person Collin Chaffin    schedule 08.08.2017
comment
+1 за это важное замечание. На самом деле, ничто не заставляет кого-либо использовать Out-Null с конвейером, поэтому лучший способ показать накладные расходы конвейера - это вызвать Out-Null с ним и без него. В моей системе для 10 000 итераций я получаю 0,576 секунды для Out-Null -InputObject $GetProcess по сравнению с 5,656 секунды (почти в 10 раз медленнее) для $GetProcess | Out-Null. - person Lance U. Matthews; 05.08.2018
comment
Привет, Коллин, спасибо за ответ. Я проверил ваши образцы, но во всех партиях [void] и $null по-прежнему работали лучше, чем | Out-Null. Я понимаю, что это из-за конвейера, и дельта сокращается с более поздними партиями, но на моей машине Out-Null не работает быстрее ни в одной из партий. - person Hinek; 07.08.2018
comment
Но, конечно, я должен согласиться с теми, кто утверждает, что производительность - это еще не все, и удобочитаемость тоже должна иметь значение. - person Hinek; 07.08.2018
comment
@Hinek Ваш комментарий предполагает, что вы упустили суть того, что говорил Коллин. Да, [void] и $null будут работать лучше, чем | Out-Null - из-за |. Попробуйте Out-Null -InputObject (expression) для сравнения. - person Jonathan Gilbert; 16.06.2020

Также существует командлет 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".
person Ocaso Protal    schedule 10.03.2011
comment
Что вы думаете о результатах небольшого теста производительности в ответе Джейсона? - person Hinek; 21.03.2011
comment
Очень интересно, особенно действительно огромная разница между Out-Null и другими методами. Думаю, я перейду на [void], хотя решение Out-Null выглядит более мощным. - person Ocaso Protal; 21.03.2011
comment
Я до сих пор не уверен, какой способ предпочитаю. Даже эта огромная разница кажется малозначительной, как уже прокомментировал Стей. - person Hinek; 22.03.2011
comment
@Hinek [void] выглядит очень ясным (хотя и не слишком мощным, как я уже сказал), вы увидите в начале строки, что в этой строке нет вывода. Так что это еще одно преимущество, и если вы сделаете Out-Null в большом цикле, производительность может быть проблемой;) - person Ocaso Protal; 22.03.2011

Я бы подумал об использовании чего-то вроде:

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, потому что совершенно ясно, что вывод не будет использоваться и будет отброшен.

person stej    schedule 10.03.2011

Лично я использую ... | Out-Null, потому что, как отмечали другие, это выглядит более «PowerShellish» по сравнению с ... > $null и [void] .... $null = ... использует определенную автоматическую переменную и может быть легко не заметить, в то время как другие методы делают очевидным с дополнительным синтаксисом, что вы намереваетесь отбросить вывод выражения. Поскольку ... | Out-Null и ... > $null стоят в конце выражения, я думаю, что они эффективно сообщают: «возьмите все, что мы сделали до этого момента, и выбросьте его», плюс вы можете проще комментировать их для целей отладки (например, ... # | Out-Null) по сравнению с помещая $null = или [void] перед выражением, чтобы определить, что произойдет после его выполнения.

Однако давайте посмотрим на другой тест: не количество времени, которое требуется для выполнения каждого варианта, а количество времени, которое требуется, чтобы выяснить, что делает каждый вариант. Работая в среде с коллегами, которые не имели опыта работы с PowerShell или даже со сценариями, я стараюсь писать свои сценарии таким образом, чтобы кто-то, кто придет через несколько лет и даже не понимает язык, на который они смотрят, может иметь имеют шанс выяснить, что он делает, поскольку они могут быть в состоянии поддержать или заменить его. Мне никогда не приходило в голову, что это причина использовать один метод вместо других, но представьте, что вы находитесь в таком положении и используете команду help или свою любимую поисковую систему, чтобы попытаться выяснить, что делает Out-Null. Вы же сразу получаете полезный результат? Теперь попробуйте проделать то же самое с [void] и $null =. Не так-то просто, правда?

Конечно, подавление вывода значения - это довольно незначительная деталь по сравнению с пониманием общей логики скрипта, и вы можете только попытаться «упростить» свой код, прежде чем торговать своей способностью писать хороший код для способность новичка читать ... не очень хороший код. Я хочу сказать, что возможно, что некоторые, кто свободно владеет PowerShell, даже не знакомы с [void], $null = и т. Д., И то, что они могут выполняться быстрее или требовать меньшего количества нажатий клавиш для ввода, не означает, что они являются лучшим способом делать то, что вы пытаетесь сделать, и то, что язык дает вам необычный синтаксис, не означает, что вы должны использовать его вместо чего-то более ясного и известного. *

* Я предполагаю, что Out-Null ясно и хорошо известно, а я не знаю, что это $true. Какой бы вариант вы ни считали наиболее понятным и доступным для будущих читателей и редакторов вашего кода (включая вас самих), независимо от времени набора или выполнения, я рекомендую именно этот вариант. ты используешь.

person Lance U. Matthews    schedule 05.08.2018