问题
Let's say you have a method or a cmdlet that returns something, but you don't want to use it and you don't want to output it. I found these two ways:
Add-Item > $null
[void]Add-Item
Add-Item | Out-Null
What do you use? Which is the better/cleaner approach? Why?
回答1:
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
.
回答2:
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".
回答3:
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
回答4:
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.
回答5:
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.
来源:https://stackoverflow.com/questions/5260125/whats-the-better-cleaner-way-to-ignore-output-in-powershell