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

发布于 2024-10-21 16:48:31 字数 1431 浏览 3 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

真心难拥有 2024-10-28 16:48:31

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

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%,而 > 则有 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 的明确原因。

I just did some tests of the four options that I know about.

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

So I would suggest that you use anything but Out-Null due to overhead. The next important thing, to me, would be readability. I kind of like redirecting to $null and setting equal to $null myself. I use to prefer casting to [Void], but that may not be as understandable when glancing at code or for new users.

I guess I slightly prefer redirecting output to $null.

Do-Something > $null

Edit

After stej's comment again, I decided to do some more tests with pipelines to better isolate the overhead of trashing the output.

Here are some tests with a simple 1000 object pipeline.

## 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

In this case, Out-Null has about a 60% overhead and > $null has about a 0.3% overhead.

Addendum 2017-10-16: I originally overlooked another option with Out-Null, the use of the -inputObject parameter. Using this the overhead seems to disappear, however the syntax is different:

Out-Null -inputObject ($(1..1000) | ?{$_ -is [int]})

And now for some tests with a simple 100 object pipeline.

## 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

Here again Out-Null has about a 60% overhead. While > $null has an overhead of about 4%. The numbers here varied a bit from test to test (I ran each about 5 times and picked the middle ground). But I think it shows a clear reason to not use Out-Null.

场罚期间 2024-10-28 16:48:31

我意识到这是一个旧线程,但对于那些将@JasonMArcher上面接受的答案视为事实的人来说,我很惊讶它没有得到纠正,我们很多人多年来都知道它实际上是管道增加了延迟,与是否有任何关系无关是否为 Out-Null。事实上,如果你运行下面的测试,你很快就会发现,多年来我们都认为它更快的相同“更快”的转换到 [void] 和 $void= ,实际上是一样慢,而且实际上非常慢,当您可以添加任何管道。换句话说,一旦你通过管道传输任何东西,不使用 out-null 的整个规则就会被扔进垃圾桶。

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

那么,这是为什么呢?简单的。通向 Out-Null 的管道速度较慢,这始终是 100% 的幻觉。然而,管道传送到任何东西都比较慢,我们不是已经通过基本逻辑知道了这一点吗?我们可能不知道慢了多少,但这些测试确实说明了如果可以避免使用管道的成本。而且,我们并不是真的 100% 错误,因为只有极少数真实情况表明 out-null 是邪恶的。什么时候?添加 Out-Null 时是添加唯一的管道活动。换句话说......像 $(1..1000) | 这样的简单命令的原因如上图Out-Null显示true。

如果您只是在上面的每个测试中向 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

I realize this is an old thread, but for those taking @JasonMArcher's accepted answer above as fact, I'm surprised it has not been corrected many of us have known for years it is actually the PIPELINE adding the delay and NOTHING to do with whether it is Out-Null or not. In fact, if you run the tests below you will quickly see that the same "faster" casting to [void] and $void= that for years we all used thinking it was faster, are actually JUST AS SLOW and in fact VERY SLOW when you add ANY pipelining whatsoever. In other words, as soon as you pipe to anything, the whole rule of not using out-null goes into the trash.

Proof, the last 3 tests in the list below. The horrible Out-null was 32339.3792 milliseconds, but wait - how much faster was casting to [void]? 34121.9251 ms?!? WTF? These are REAL #s on my system, casting to VOID was actually SLOWER. How about =$null? 34217.685ms.....still friggin SLOWER! So, as the last three simple tests show, the Out-Null is actually FASTER in many cases when the pipeline is already in use.

So, why is this? Simple. It is and always was 100% a hallucination that piping to Out-Null was slower. It is however that PIPING TO ANYTHING is slower, and didn't we kind of already know that through basic logic? We just may not have know HOW MUCH slower, but these tests sure tell a story about the cost of using the pipeline if you can avoid it. And, we were not really 100% wrong because there is a very SMALL number of true scenarios where out-null is evil. When? When adding Out-Null is adding the ONLY pipeline activity. In other words....the reason a simple command like $(1..1000) | Out-Null as shown above showed true.

If you simply add an additional pipe to Out-String to every test above, the #s change radically (or just paste the ones below) and as you can see for yourself, the Out-Null actually becomes FASTER in many cases:

$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
你曾走过我的故事 2024-10-28 16:48:31

还有 Out-Null 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".

There is also the Out-Null cmdlet, which you can use in a pipeline, for example, Add-Item | Out-Null.

Manual page for 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".
邮友 2024-10-28 16:48:31

我会考虑使用类似的方法:

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

I would consider using something like:

function GetList
{
  . {
     $a = new-object Collections.ArrayList
     $a.Add(5)
     $a.Add('next 5')
  } | Out-Null
  $a
}
$x = GetList

Output from $a.Add is not returned -- that holds for all $a.Add method calls. Otherwise you would need to prepend [void] before each the call.

In simple cases I would go with [void]$a.Add because it is quite clear that output will not be used and is discarded.

嘦怹 2024-10-28 16:48:31

就我个人而言,我使用 ... | Out-Null 因为,正如其他人评论的那样,与 ... > 相比,这看起来更像是“PowerShellish”方法。 $null[void] ...$null = ... 正在利用特定的 自动变量 并且很容易被忽视,而其他方法则通过额外的语法使您明显地知道您打算丢弃表达式的输出。因为 ... | Out-Null...> $null 出现在表达式的末尾,我认为它们有效地传达了“将我们到目前为止所做的一切都扔掉”,而且您可以将它们注释掉以方便调试(例如 ... # | Out-Null),与在要确定的表达式之前放置 $null =[void] 相比执行后会发生什么。

不过,让我们看一下不同的基准:不是执行每个选项所需的时间,而是弄清楚每个选项的作用所需的时间。在与没有使用 PowerShell 甚至根本没有脚本编写经验的同事一起工作的环境中,我倾向于尝试以一种方式编写脚本,以便多年后出现的甚至可能不理解他们正在查看的语言的人也可以因为他们可能必须支持或替换它,所以要努力弄清楚它在做什么。到目前为止,我从来没有想到过使用一种方法而不是其他方法的理由,但想象一下您处于那个位置,并且您使用 help 命令或您最喜欢的搜索引擎来尝试找出答案Out-Null 的作用。您立即得到有用的结果,对吧?现在尝试对 [void]$null = 执行相同的操作。没那么容易,不是吗?

诚然,与理解脚本的整体逻辑相比,抑制值的输出是一个相当小的细节,并且在你用编写良好代码的能力来换取一个好的代码之前,你只能尝试“简化”你的代码。新手阅读不太好的代码的能力。我的观点是,一些精通 PowerShell 的人可能甚至不熟悉 [void]$null = 等,仅仅因为这些可能会执行更快或更少的击键次数并不意味着它们是完成您想要做的事情的最佳方式,并且仅仅因为一种语言为您提供了古怪的语法并不意味着您应该使用它而不是更清晰和更清晰的东西better-known.*

* 我假设 Out-Null 是清楚且众所周知的,但我不知道是 <代码>$true。无论您认为哪个选项对您的代码的未来读者和编辑者(包括您自己)来说最清晰且最容易访问,无论输入时间或执行时间如何,这都是我推荐的选项你用。

Personally, I use ... | Out-Null because, as others have commented, that looks like the more "PowerShellish" approach compared to ... > $null and [void] .... $null = ... is exploiting a specific automatic variable and can be easy to overlook, whereas the other methods make it obvious with additional syntax that you intend to discard the output of an expression. Because ... | Out-Null and ... > $null come at the end of the expression I think they effectively communicate "take everything we've done up to this point and throw it away", plus you can comment them out easier for debugging purposes (e.g. ... # | Out-Null), compared to putting $null = or [void] before the expression to determine what happens after executing it.

Let's look at a different benchmark, though: not the amount of time it takes to execute each option, but the amount of time it takes to figure out what each option does. Having worked in environments with colleagues who were not experienced with PowerShell or even scripting at all, I tend to try to write my scripts in a way that someone coming along years later that might not even understand the language they're looking at can have a fighting chance at figuring out what it's doing since they might be in a position of having to support or replace it. This has never occurred to me as a reason to use one method over the others until now, but imagine you're in that position and you use the help command or your favorite search engine to try to find out what Out-Null does. You get a useful result immediately, right? Now try to do the same with [void] and $null =. Not so easy, is it?

Granted, suppressing the output of a value is a pretty minor detail compared to understanding the overall logic of a script, and you can only try to "dumb down" your code so much before you're trading your ability to write good code for a novice's ability to read...not-so-good code. My point is, it's possible that some who are fluent in PowerShell aren't even familiar with [void], $null =, etc., and just because those may execute faster or take less keystrokes to type, doesn't mean they're the best way to do what you're trying to do, and just because a language gives you quirky syntax doesn't mean you should use it instead of something clearer and better-known.*

* I am presuming that Out-Null is clear and well-known, which I don't know to be $true. Whichever option you feel is clearest and most accessible to future readers and editors of your code (yourself included), regardless of time-to-type or time-to-execute, that's the option I'm recommending you use.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文