30

In a PowerShell script automating some SVN tasks I have the following function:

function SvnUrlExists($url)
{
  svn info $url | out-null 2>&1
  return $?
}

Since this explicitly tests whether some SVN repository URL exists, I am not interested at all in any error output. However, despite everything I found about redirecting stderr in PowerShell suggesting 2>&1 to redirect it to stdout, this still outputs an error message:

svn: warning: W170000: URL 'blahblah' non-existent in revision 26762
svn: E200009: Could not display info for all targets because some targets don't exist

Unfortunately, this severely messes up the output of my script.

What am I doing wrong, and how should I suppress this error output?

sbi
  • 212,637
  • 45
  • 247
  • 432

5 Answers5

33

If you want to suppress only standard error, use:

svn info $url 2>$null
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Daniel
  • 2,921
  • 2
  • 29
  • 29
30

Just in case someone else googles for similar terms as I did:

After I have been banging my forehead against this for hours, of course I found the solution within minutes after posting the question here:

svn info $url 2>&1 | out-null

This works like a charm.

sbi
  • 212,637
  • 45
  • 247
  • 432
  • Also, if you have a larger command you can wrap it in `$() | out-null` to get the same effect. For example: `$( svn info $url 2>&`) | out-null`. I do this when the command is very long, or I need to break it over a few lines in a script. – Nick Aug 15 '12 at 15:53
  • @Nick: Ah, thanks. However, wouldn't it have to be `$( svn info $url ) 2>&1 | out-null`? (Note the placement of the `2>&1`.) – sbi Aug 16 '12 at 09:34
  • Oh wow, I completely misread your post. Yes, it should be `$(svn info $url) | out-null`. It depends on where you want the error checking to happen for the `2>&1`. I can't say without testing it, but I don't think it should matter if it is inside the `)` or outside. You might actually be able to just leave the `2>&1` off completely, like I said, without testing I can't be sure. – Nick Aug 16 '12 at 14:41
  • it works, but if you use it in a script, it will cause the error to stop the script. This might not be an intended side effect. – cmcginty Apr 24 '14 at 03:10
  • @Casey: "In a PS script [...] I have the following function". – sbi Apr 24 '14 at 06:18
  • 1
    I cam across this because I had a `git commit` that I couldn't get to stfu when being ran via PowerShell... I'm very close to having PS instead invoke 'git bash' t handle the git stuff. At least I can trust bash to silence stuff. – thecoshman Feb 18 '19 at 16:45
8

One can also do this:

svn info $url *> $null

See Suppress console output in PowerShell

about_Redirection

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Zombo
  • 1
  • 55
  • 342
  • 375
5

The voted answer generates an error for me. The solution ended up being the following:

cmd /c "MyProgram MyArguments 2>&1" | Out-Null
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
David Bertrand
  • 311
  • 3
  • 4
  • 3
    Redirecting stderr to stdout will still generate an error and stop script execution if you have $ErrorActionPreference = 'Stop'. But the error will not happen if you do not redirect stderr to stdout. Weird! – Rafał Kłys Oct 10 '17 at 12:44
  • @RafałKłys: Weird, indeed; it is a _bug_: see https://github.com/PowerShell/PowerShell/issues/4002 – mklement0 Oct 10 '17 at 13:17
  • For anybody tracking this, that was duped to https://github.com/PowerShell/PowerShell/issues/3996 and there will be a fix in version v7.1.0 (still in preview), maybe hidden behind the flag `PSNotApplyErrorActionToStderr` – Carl Walsh Nov 07 '20 at 00:47
5

tl;dr

function SvnUrlExists($url)
{

  # Suppress all output streams (external stdout and stderr in this case)
  # To suppress stderr output only, use 2>$null
  svn info $url *>$null 

  # For predictable results with external programs, 
  # infer success from the *process exit code*, not from the automatic $? variable.
  # See https://github.com/PowerShell/PowerShell/issues/10512
  $LASTEXITCODE -eq 0
}

Your own answer effectively addresses the redirection issue.

Steven Penny's answer proposes *>$null, i.e. suppressing all output streams as a convenient alternative - it obviates the need for Out-Null, which I generally suggest replacing with $null = ... - see this answer.

However, there's another problem with the code in your question:

While it may work with your particular command, $?, unfortunately, is not a robust indicator of whether an external program succeeded or not - use $LASTEXITCODE -eq 0 instead, because - due to a bug as of PowerShell Core 7.0.0-preview.3, reported on GitHub here - $? can end up reflecting $false even when $LASTEXITCODE is 0 (unequivocally signaling success).

  • Update: If and when the pre-v7.2 experimental feature named PSNotApplyErrorActionToStderr becomes an official feature, this problem will go away - see this answer for more information.

As for what you tried in your question:

svn info $url | out-null 2>&1  # WRONG
  • Only success output is sent through to the pipeline (stdout output from external programs is sent to PowerShell's success output stream).

  • Redirections such as 2>&1 act on individual commands in a pipeline, not the pipeline as a whole.

  • Therefore, if svn info $url produces stderr output, it prints straight to the host (console) - Out-Null never sees it.

mklement0
  • 312,089
  • 56
  • 508
  • 622
  • 2
    "Redirections such as 2>&1 act on individual commands in a pipeline, not the pipeline as a whole." - This is what solved the problem I was having. – Matt Mills Feb 24 '20 at 16:58