Question:
There are four ways to suppress an output:
- Redirection to
$null
variable
1234PS C:\> 1; $(2; return) > $null; 313 - Piping to
Out-Null
cmdlet
1234PS C:\> 1; $(2; return) | Out-Null; 312 - Casting to
[void]
type
1234PS C:\> 1; [void]$(2; return); 312 - Assignment to
$null
variable
1234PS C:\> 1; $null = $(2; return); 312
All four cases are expected to be equivalent.
Why redirection to $null
behaves different? Have I faced a bug?
An additional example
This example shows unexpected behavior of > $null
command in PS 2.0:
1 2 3 4 5 |
PS C:\> 1; $(Write-Output 2; Write-Host 3; return; Write-Host 4) > $null; 5 1 3 5 |
return
command acts as if it exits from some nested context (though there is no command which creates it), stops $()
expression execution and then continues the execution (when it shouldn’t) in the current context to the Write-Output 5
command.
BEHAVIOR EXPLANATIONS
(from wOxxOm‘s answer)
- in PS 1.0 and 2.0
> $null
operation is executed before$()
expression and suppresses its output;return
command does not exit from the current context (considered a BUG), but stops$()
expression execution - in PS 3.0 and newer
> $null
operation is executed before$()
expression and suppresses its output in all cases;return
command exits from the current context completely | Out-Null
,[void]
,$null =
operations are executed after$()
expression and suppress its output if there is noreturn
command in it;return
command exits from the current context completely
SUMMARY
Different methods for suppressing command output:
... > $null
redirection to$null
variable
Bug in PS 1.0 and 2.0. In PS 3.0+ output may differ from other methods... | Out-Null
piping toOut-Null
cmdlet
Performance issues *[void]...
casting to[void]
type
Advisable$null = ...
assignment to$null
variable
Advisable
Answer:
2
is actually executed asWrite-Output 2
$()
executes the enclosed code in the same context, it doesn’t create a new context.Things that create a new context are scriptblocks like
& { ... }
,1..2 | ForEach { ... }
,
({ ... }).Invoke()
,select @{N='calculated property'; E={$_.foo}}
and functions.
- Thus,
$( return )
exits from the current context so nothing should be evaluated after that (in other words PowerShell 1.0 and 2.0 have a bug).
Redirecting the output stream:
1 2 |
1; $(2; return) > $null; 3 |
The output stream itself of the entire $()
expression is suppressed with >$null
, which is decided before the expression is evaluated, return
exits from the current context before 3
gets a chance.
PS 3 (and newer) correctly prints only 1
:
1
PS 1 and 2 incorrectly print both numbers and indeed it’s a bug:
1
3
Processing the output stream:
1 2 3 4 |
1; [void]$(2; return); 3 1; $null = $(2; return); 3 1; $(2; return) | Out-Null; 3 |
1
2
2
is pushed to the output stream here, then return
exits the current context before subsequent operation can take place (casting, assigning, pipelining).
As for performance differences, see this answer: | Out-Null
is the slowest because it creates a pipeline which is a complex process; the other methods discard the output, no extras created.