简体   繁体   中英

Suppress external command error output from Powershell $error

In my profile, I've customised the prompt via the prompt function to embed git branch information:

function prompt
{
    $prefix = ""
    if ((test-path ".git") -or (test-path ".gitdir") -or ((git rev-parse --is-inside-work-tree 2> $null) -eq "true")) {
        $prefix = "[git:" + (& git symbolic-ref --short HEAD) + "]"
    }

    write-host "PS $prefix $(get-location) >" -nonewline -foregroundcolor DarkMagenta
    return " "
}

The problem however is that when I'm outside of a git tree, the git rev-parse part of the check inserts an error into $error even though I'm redirecting errors to $null.

This means that $error gets polluted with the following error, as it is generated every time the prompt renders:

git : fatal: Not a git repository (or any of the parent directories): .git
At C:\temp\prompt.ps1:4 char:64
    + ... ".gitdir") -or ((git rev-parse --is-inside-work-tree 2> $null) -eq "t ...
    +                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (fatal: Not a gi...ectories): .git:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Running interactively I've noticed that the 2> $null does suppress the error to the console, but the error still appears in $error:

PS C:\temp> $error
PS C:\temp> git rev-parse --is-inside-work-tree 2> $null
PS C:\temp> $error
git : fatal: Not a git repository (or any of the parent directories): .git
At line:1 char:1
+ git rev-parse --is-inside-work-tree 2> $null
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (fatal: Not a gi...ectories): .git:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

PS C:\temp>

I've tried wrapping the command in try {...} catch {} , and also using invoke-command with an erroraction of ignore, both with no luck:

PS c:\temp> $error.clear()
PS c:\temp> $error
PS c:\temp> invoke-command -scriptblock { git rev-parse --is-inside-work-tree 2> $null } -erroraction ignore
PS c:\temp> $error
git : fatal: Not a git repository (or any of the parent directories): .git
At line:1 char:31
+ ... d -scriptblock { git rev-parse --is-inside-work-tree 2> $null } -erro ...
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (fatal: Not a gi...ectories): .git:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

PS c:\temp> $error.clear()
PS c:\temp> $error
PS c:\temp> try { git rev-parse --is-inside-work-tree 2> $null } catch { }
PS c:\temp> $error
git : fatal: Not a git repository (or any of the parent directories): .git
At line:1 char:7
+ try { git rev-parse --is-inside-work-tree 2> $null } catch { }
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (fatal: Not a gi...ectories): .git:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

PS c:\temp>

How can I suppress this error from adding to $error so it stays clean?

Unfortunately, as of PowerShell Core 6.2.1 / Windows PowerShell v5.1, using 2>$null to suppress stderr output from an external program unexpectedly still takes a detour via Powershell's error stream (stream 2 ), so the output is still recorded in $Error . This known problem is described in this GitHub issue .

As a workaround, you can call git via cmd /c (or sh -c on Unix) and let it do the redirection:

# Windows
cmd /c 'git rev-parse --is-inside-work-tree 2>NUL'

# Linux, macOS
sh -c 'git rev-parse --is-inside-work-tree 2>/dev/null'

As you state, this will correctly pass git 's exit code through so you can determine success via $LASTEXITCODE afterwards.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM