在PowerShell中忽略输出的更好(更简洁)的方法是什么?[关闭]


134

假设您有一个返回值的方法或cmdlet,但您不想使用它,也不想输出它。我发现了两种方法:

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

你用什么?哪种方法更好/更清洁?为什么?


1
像[void]版本...尚不适合我,但我会尽力记住它。
Massif

Answers:


181

我只是对我所知道的四个选项做了一些测试。

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

编辑

在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


1
我通常对语言行中的内容使用VOID,如果它已经是一个很大的冗长管道,则将其
废止

25
Out-Null可能是开销。但是..如果将一个对象传递到Out-Null0.076毫秒,恕我直言,对于脚本语言来说,它仍然是非常好的:)
stej

1
我对此有些混乱,通过使用Out-Null -InputObject($(1..1000)|?{$ _ -is [int]}),我在[void]和> $ null上获得了最佳性能。
tomohulk

1
好一点,这似乎没有明显的开销。
JasonMArcher '17

5
虽然拥有基准来比较完成某件事的不同方式总是很有益的,但我们不要忽视这里可以得出的另一个结论:除非您不得不舍弃成千上万次的性能差异可以忽略不计。而且,如果这真的对您来说很重要,那么您一开始就不应该使用PowerShell。如果不对选项在这些方面的排名做出任何判断,那么牺牲速度来提高其他质量(例如可读性和表达程序员的意图)并不一定是一件坏事。
培根

22

我意识到这是一个旧线程,但是对于那些接受@JasonMArcher上面接受的答案为事实的人,我感到惊讶的是它没有得到纠正,我们许多人已经知道很多年了,实际上这是PIPELINE增加了延迟,而与是否它是否为零。实际上,如果您运行下面的测试,您会很快看到对[void]和$ void =的相同“快速”转换,多年来我们都认为它更快,实际上只是很慢,而实际上您可以添加任何流水线。换句话说,只要您通过管道传输任何内容,就不使用无效值的整个规则就会变成垃圾。

证明,下面列表中的最后3个测试。可怕的无效值是32339.3792毫秒,但是等等-强制转换为[void]有多快?34121.9251毫秒?!?WTF?这些是我系统上的REAL#,实际上转换为VOID较慢。= $ null怎么样?34217.685ms .....仍然很慢!因此,如最后三个简单测试所示,在许多情况下,已经使用了管道时,Out-Null实际上更快。

那么,为什么呢?简单。一直到向零输出的管道变慢是一种幻觉。但是,“向任何东西滑动”是比较慢的,我们不是已经通过基本逻辑知道了吗?我们可能还不知道慢得多,但是如果可以避免的话,这些测试肯定可以说明使用管道的成本。而且,我们并不是真的100%错了,因为有非常少的虚假情况是真实的情况。什么时候?添加Out-Null时,将添加仅管道活动。换句话说....一个简单命令的原因,例如$(1..1000)| 如上所示,Out-Null显示为true。

如果您只是将额外的管道添加到Out-String到上面的每个测试中,则#会发生根本变化(或仅粘贴下面的代码),并且如您所见,在许多情况下,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

+1表示这一点。实际上,根本没有强迫任何人使用Out-Null管道的问题,因此,显示管道开销的最佳方法是在Out-Null有或没有管道的情况下进行调用。在我的系统上,对于10,000次迭代,我的速度为0.576秒,Out-Null -InputObject $GetProcess而的为5.656秒(慢近10倍)$GetProcess | Out-Null
培根

嗨,柯林,谢谢您的回答。我跑你的样品,但在所有批次[void],并$null仍执行好过| Out-Null。我知道这是因为管线,并且增量在以后的批次中缩小了,但是在我的机器Out-Null上,这两个批次中的执行速度都不快。
Hinek

但是,当然,我必须同意那些认为性能不是一切的因素,可读性也应考虑在内。
Hinek

@Hinek您的评论暗示您错过了Collin在说什么。是的,[void]并且由于$null会比| Out-Null- 表现更好|。尝试Out-Null -InputObject (expression)进行比较。
乔纳森·吉尔伯特

19

还有Out-Nullcmdlet,您可以在管道中使用该cmdlet,例如Add-Item | 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".

您如何看待Jason回答中的小型基准测试的结果?
Hinek 2011年

非常有趣,特别是Out-Null与其他方法之间的巨大差异。我认为[void]即使Out-Null解决方案看起来更“强大”,我也将切换到该版本。
奥卡索·普罗塔尔(Ocaso Protal)2011年

我仍然不确定,我首选的方式是什么。正如Stej早已评论过的那样,即使这种巨大差异似乎也并不重要。
Hinek 2011年

2
@Hinek [void]看起来很清晰(我没有说过powershellish),您会在该行的开头看到该行中没有输出。因此,这是另一个优势,如果您大循环进行出零,则性能可能会成为问题;)
Ocaso Protal 2011年

11

我会考虑使用类似:

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因为很明显,将不会使用输出并将其丢弃。


2

我个人使用它... | Out-Null是因为,正如其他人评论的那样,与... > $null和相比,它看起来更像是“ PowerShellish”方法[void] ...$null = ...正在利用一个特定的自动变量,并且很容易被忽略,而其他方法通过附加的语法使其变得显而易见,即您打算丢弃表达式的输出。因为... | Out-Null并且... > $null在表达式的结尾,我认为他们有效地交流了“把到目前为止所做的一切都丢掉了”,而且... # | Out-Null与放置之前$null =[void] 之后相比,您可以出于调试目的(例如)将它们注释掉更容易该表达式确定执行发生的情况。

但是,让我们看一个不同的基准:不是执行每个选项所花费的时间,而是弄清楚每个选项所执行的花费的时间。在与没有使用PowerShell甚至根本没有脚本经验的同事一起工作的环境中,我倾向于尝试编写脚本,以使几年后甚至不了解他们所使用语言的人都可以拥有一个脚本。因为他们可能不得不支持或替换它,所以有机会弄清楚它在做什么。直到现在,我从来没有将它作为使用其他方法的理由,但是想象一下您处于那个位置,并且您使用help命令或您喜欢的搜索引擎来尝试找出什么Out-Null做。您会立即获得有用的结果,对吗?现在尝试做同样的[void]$null =。不是那么容易,是吗?

当然,与理解脚本的整体逻辑相比,抑制值的输出是一个非常小的细节,并且您只能在尝试为代码编写良好代码的能力之前,对代码进行“精简”。新手的阅读能力……不是很好。我的观点是,它可能是一些谁在PowerShell中流利甚至不熟悉[void]$null =等等,只是因为那些可以更快地执行或花费更少的击键类型,并不意味着他们是做的最好的方法您正在尝试做的事情,仅仅是因为一种语言为您提供了古怪的语法,并不意味着您应该使用它而不是更清晰,更广为人知的语言。*

*我想这Out-Null很清楚而且众所周知,我不知道是什么$true。无论何时键入代码或执行时间如何,无论觉得哪种方式最清晰,并且对于以后的代码阅读者和编辑者(包括您自己),最容易使用的,这是我建议您使用的选项。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.