7

As part of a script I am running git clean -fd. It typically outputs a bunch of files that are cleaned up. I would like to suppress this output.

I tried git clean -fd | Out-Null but it did not seem to work. Googling returned no options for git to suppress output, so is there another PowerShell method I can use? Or am I doing something wrong? It may be worth noting that the PowerShell script itself is being executed from within a .bat file.

mklement0
  • 382,024
  • 64
  • 607
  • 775

2 Answers2

8

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Thanks, @nmbell: I've have folded your feedback into the answer and have fleshed it out; please see the newly added bottom section. – mklement0 Mar 20 '21 at 16:39
5

Just add option -q:

git clean -fdq
phd
  • 82,685
  • 13
  • 120
  • 165