phd's helpful answer offers the best solution for the case at hand.
As for why ... | Out-Null
wasn't effective:
Out-Null
suppresses only stdout output from external programs such as git
, but not stderr output.
git
, like many CLIs (console / terminal programs), uses the stderr stream not just to report errors, but also for status information - basically, anything that's not data.
To suppress both stdout and stderr output, use *> $null
:
git clean -fd *> $null
Note: *> $null
suppresses all output streams; while external programs only have 2 (stdout and stderr), applying *>$null
to a PowerShell-native command silences all 6 output streams.
See about_Redirection for more information.
Optional reading: Selective stream redirection from external programs:
Building on feedback from nmbell:
>$null
(or 1>$null
) can be used to suppress stdout output selectively, which is effectively the same as | Out-Null
.
2>$null
can be used to suppress stderr output selectively.
*>$null
, as discussed above, silences both (all) streams.
Of course, instead of $null
for suppressing output, the redirection target may also may be a file (name or path).
Note:
PowerShell processes output from external programs line by line in its pipeline, and if the output is captured in a variable ($out = ...
) and comprises 2 or more lines, it is stored as an array ([object[]]
) of lines (strings).
PowerShell only ever "speaks text" (uses strings) with external programs, both when sending and receiving data, which means that character-encoding issues may come into play.
See this answer for more information on both these aspects.
Scenarios with examples:
Setup:
# Construct a platform-appropriate command, stored in a script block ({ ... })
# that calls an external program (the platform-native shell) that outputs
# 1 line of stdout and 1 line of stderr output each, and can later be
# invoked with `&`, the call operator.
$externalCmd = if ($env:OS -eq 'Windows_NT') { # Windows
{ cmd /c 'echo out & echo err >&2' }
} else { # Unix (macOS, Linux)
{ sh -c 'echo out; echo err >&2' }
}
Capture stdout, pass stderr through:
PS> $captured = & $externalCmd; "Captured: $captured"
err # Stderr output was *passed through*
Captured: out # Captured stdout output.
Capture stdout, suppress stderr output, with 2>$null
:
PS> $captured = & $externalCmd 2>$null; "Captured: $captured"
Captured: out # Captured stdout output - stderr output was suppressed.
Capture both stdout and stderr, with *>&1
:
PS> $captured = & $externalCmd *>&1 | % ToString; "Captured: $captured"
Captured: out err # *Combined* stdout and stderr output.
Note:
% ToString
is short for ForEach-Object ToString
, which calls the .ToString()
method on each output object, which ensures that the System.Management.Automation.ErrorRecord
instances that PowerShell wraps stderr lines in are converted back to strings.
$captured
receives a 2-element array ([object[]]
) of lines - containing the stdout and stderr line as elements, respectively; it is PowerShell's string interpolation that turns them into a single-line, space-separated string in this case.
Capture only stderr, suppress stdout:
PS> $captured =
& $externalCmd *>&1 |
? { $_ -is [System.Management.Automation.ErrorRecord] } |
% ToString; "Captured: $captured"
Captured: err # Captured stderr output *only*.
Note:
? { $_ -is [System.Management.Automation.ErrorRecord] }
is short for
Where-Object { $_ -is [System.Management.Automation.ErrorRecord] }
, which passes only stderr lines - identifiable via the wrapper type being tested for - through, and % ToString
again converts them back to strings.
This technique is neither obvious nor convenient; GitHub suggestion #4332 proposes a syntax such as 2> variable:stderr
to support redirecting streams to variables, such as $stderr
in this case.