在PowerShell中忽略输出的更好(更干净)的方法是什么?

时间:2011-03-10 13:15:52

标签: powershell null void

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

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

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

5 个答案:

答案 0 :(得分:155)

我刚刚对我所知道的四个选项进行了一些测试。

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的明确理由。

答案 1 :(得分:18)

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

答案 2 :(得分:13)

我意识到这是一个旧线程,但对于那些将@ JasonMArcher接受的上述答案作为事实的人,我很惊讶它没有得到纠正我们许多人已经知道多年它实际上是PIPELINE添加延迟和没有是否是Out-Null。实际上,如果你运行下面的测试,你会很快看到同样的“更快”的转换为[void]和$ void =多年来我们都认为它更快,实际上只是很慢,实际上非常慢你添加任何流水线无论如何。换句话说,只要你输出任何东西,不使用out-null的整个规则就会进入垃圾桶。

证明,下面列表中的最后3个测试。可怕的Out-null是32339.3792毫秒,但等待 - 加速到[void]的速度有多快? 34121.9251 ms?!? WTF?这些是我系统上的REAL #s,转换为VOID实际上是SLOWER。 = $ null怎么样? 34217.685ms .....还是friggin SLOWER!因此,正如最后三个简单测试所示,在管道已经投入使用的情况下,Out-Null实际上更快。

那么,为什么呢?简单。对Out-Null的管道来说,它总是100%幻觉。然而,PIPING TO ANYTHING速度较慢,我们是不是已经知道通过基本逻辑?我们可能不知道这么慢,但这些测试确实讲述了如果你可以避免使用管道的成本。并且,我们并没有真正100%错误,因为有一小部分真实场景,其中out-null是邪恶的。什么时候?添加Out-Null时添加ONLY管道活动。换句话说....之所以像$(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

答案 3 :(得分: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,因为很明显输出不会被使用并被丢弃。

答案 4 :(得分:1)

我个人使用import videojs from 'video.js'; class MainMediaController { public static readonly INTERVAL = 250; protected _playerId: string; protected _duration: number; protected _mediaController: videojs.Player; protected _childPlayers: videojs.Player[]; protected _currentTime: number; private _interval: number; private _intervalId: number; constructor(playerId: string, recordingDuration: number, childPlayers: videojs.Player[]) { this._playerId = playerId; // id of the player at the bottom of the page which will be served as the main timeline this._duration = recordingDuration; this._interval = MainMediaController.INTERVAL; this._childPlayers = childPlayers; this._currentTime = 0; } public async init() { this._mediaController = videojs(this._playerId); // await for ready state await new Promise((resolve, reject) => { this._mediaController.ready(() => { resolve(); }); }); // set duration for a correct seek bar (longest.endTime - first.startTime) this._mediaController.duration(this._duration); } public play(){ // update UI every 250ms this._intervalId = setInterval(this.intervalStep.bind(this), this._interval); for(let player of this._childPlayers){ player.play(); } } private intervalStep(){ this._currentTime += 0.250; // 250ms this._mediaController.currentTime(this._currentTime); this._mediaController.trigger("timeupdate"); // trigger() is accessible don't worry } public pause(){...} public stop(){...} public seek(){...} } 是因为,正如其他人评论的那样,与... | Out-Null... > $null相比,它看起来更像是“ PowerShellish”方法。 [void] ...正在利用特定的automatic variable,并且很容易被忽略,而其他方法通过附加的语法使其变得显而易见,即您打算丢弃表达式的输出。因为$null = ...... | Out-Null出现在表达式的末尾,所以我认为它们可以有效地交流“把到目前为止所做的一切都扔掉”,而且您可以注释掉它们以便调试用途(例如... > $null),而不是将... # | Out-Null$null =放在表达式前 以确定执行它们后之后。 / p>

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

与理解脚本的整体逻辑相比,禁止显示值的输出是一个相当小的细节,并且您只能在尝试交换良好的编写能力之前尝试“精简”代码。新手阅读代码的能力...不是很好。我的观点是,可能一些精通PowerShell的人甚至不熟悉[void]$null =等,仅仅因为这些命令执行速度更快或键入的击键次数更少,就不会了。这并不意味着它们是完成您要尝试的工作的最佳方法,而仅仅是一种语言为您提供了古怪的语法,并不意味着您应该使用它而不是更清晰,更知名的东西。 *

* 我假设[void]清晰且广为人知,我不知道它是$null =。我建议您选择哪种 选项对您的代码(包括您自己)的将来的读者和编辑者来说最清晰,最容易使用,而不论输入时间或执行时间如何,这就是我建议的选项您使用。