禁止从 Powershell $error 输出外部命令错误

Chr*_*s J 4 powershell

prompt在我的个人资料中,我通过嵌入 git 分支信息的函数自定义了提示:

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 " "
}
Run Code Online (Sandbox Code Playgroud)

然而问题是,当我在 git 树之外时,即使我将错误重定向到 $null,git rev-parse检查的部分也会插入错误。$error

这意味着 $error 会受到以下错误的污染,因为每次提示呈现时都会生成该错误:

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
Run Code Online (Sandbox Code Playgroud)

交互式运行我注意到它2> $null确实抑制了控制台的错误,但错误仍然出现在 $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>
Run Code Online (Sandbox Code Playgroud)

我尝试将命令包装在 中try {...} catch {},并使用invoke-command忽略的错误操作,但都没有成功:

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>
Run Code Online (Sandbox Code Playgroud)

如何抑制此错误的添加,$error使其保持干净?

mkl*_*nt0 5

不幸的是,从 PowerShell Core 6.2.1 / Windows PowerShell v5.1 开始,使用2>$null抑制外部程序的 stderr 输出仍然会绕道 Powershell 的错误流 (stream 2),因此输出仍然记录在$Error. 此 GitHub 问题中描述了此已知问题。

作为解决方法,您可以调用gitvia cmd /c(或sh -c在 Unix 上)并让它执行重定向:

# 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'
Run Code Online (Sandbox Code Playgroud)

正如您所说,这将正确地传递 的git退出代码,以便您可以通过$LASTEXITCODE之后确定成功。