使用 Powershell 将标准错误和标准输出重定向到两个不同的位置

9

如何将错误输出重定向到日志文件,将标准输出重定向到对象?

  • 将stderr重定向到logfile
  • 将stdout重定向到对象

我查看了以下内容:

>>2>>只能重定向到文件。
-RedirectStandardOutput-RedirectStandardError又只能再次重定向到文件。
| Out-File无法重定向stderr。
| Tee-Object同样有这个问题。


6
. {$object = command} 2>&1 | Out-File logfile - user4003407
@PetSerAl - 你能解释一下吗?2>1会将标准输出和错误输出都重定向到日志文件中,是吗? - Jamie Marshall
1
是的。但是赋值操作($object =)已经捕获了常规输出,因此在那一点上它已经从输出流中删除了。 - Ansgar Wiechers
@PetSerAl - 搞定了。非常简洁的解决方案。谢谢。 - Jamie Marshall
3个回答

19

stdoutstderr输出流合并,可以像PetSerAl评论的那样操作,尽管语法不是最直观的。

2>&1这个奇怪的语法意味着将stderr(流2)添加到stdout(流1)中。由于这实际上并不是您想要的,因此请尝试将MS页面上的另一个示例适应为PowerShell:

或者,您可以将输出重定向到一个地方,将错误重定向到另一个地方。

dir file.xxx > output.msg 2> output.err

因此,

$ret = myCommand 2> errors.log

应该将错误信息发送到日志文件中,并将非错误信息存储在$ret变量中。


感谢vonPryz。我在使用PowerShell时遇到的一个大问题是找不到关于该怎么做的文档,而是需要了解“为什么”和“如何”工作。知道2>&1将stderr输入到stdout中是关键。 - Jamie Marshall

7

关于重定向 MSDN文章中有详细的解释。

最小完整可验证示例stdout到管道):

PS D:\PShell> -1,5,0,2| ForEach-Object { 15/$_ } 2>"$env:temp\err.txt" | Write-Output
-15
3
7.5

PS D:\PShell> Get-Content "$env:temp\err.txt"
Attempted to divide by zero.
At line:1 char:28
+ -1,5,0,2| ForEach-Object { 15/$_ } 2>"$env:temp\err.txt" | Write-Outpu ...
+                            ~~~~~
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException


PS D:\PShell> 

另一个例子(stdout转为对象):
PS D:\PShell> $x = -1,5,0,2| ForEach-Object { 15/$_} 2>"$env:temp\err.txt"

PS D:\PShell> $x
-15
3
7.5

-1
function GetAnsVal {
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true)][System.Object[]][AllowEmptyString()]$Output,
          [Parameter(Mandatory=$false, ValueFromPipeline=$true)][System.String]$firstEncNew,
          [Parameter(Mandatory=$false, ValueFromPipeline=$true)][System.String]$secondEncNew
    )
    function ConvertTo-Encoding ([string]$From, [string]$To){#"UTF-8" "CP866" "ASCII" "windows-1251"
        Begin{
            $encFrom = [System.Text.Encoding]::GetEncoding($from)
            $encTo = [System.Text.Encoding]::GetEncoding($to)
        }
        Process{
            $Text=($_).ToString()
            $bytes = $encTo.GetBytes($Text)
            $bytes = [System.Text.Encoding]::Convert($encFrom, $encTo, $bytes)
            $encTo.GetString($bytes)
        }
    }
    $all = New-Object System.Collections.Generic.List[System.Object];
    $exception = New-Object System.Collections.Generic.List[System.Object];
    $stderr = New-Object System.Collections.Generic.List[System.Object];
    $stdout = New-Object System.Collections.Generic.List[System.Object]
    $i = 0;$Output | % {
        if ($_ -ne $null){
            if ($_.GetType().FullName -ne 'System.Management.Automation.ErrorRecord'){
                if ($_.Exception.message -ne $null){$Temp=$_.Exception.message <#| ConvertTo-Encoding $firstEncNew $secondEncNew#>;$all.Add($Temp);$exception.Add($Temp)}
                elseif ($_ -ne $null){$Temp=$_ <#| ConvertTo-Encoding $firstEncNew $secondEncNew#>;$all.Add($Temp);$stdout.Add($Temp)}
            } else {
                #if (MyNonTerminatingError.Exception is AccessDeniedException)
                $Temp=$_.Exception.message <#| ConvertTo-Encoding $firstEncNew $secondEncNew#>;
                $all.Add($Temp);$stderr.Add($Temp)
            }   
         }
    $i++
    }
    [hashtable]$return = @{}
    $return.Meta0=$all;$return.Meta1=$exception;$return.Meta2=$stderr;$return.Meta3=$stdout;
    return $return
}
Add-Type -AssemblyName System.Windows.Forms;
& C:\Windows\System32\curl.exe 'api.ipify.org/?format=plain' 2>&1 | set-variable Output;
$r = & GetAnsVal $Output
[Console]::Write("exception:`n");
$r.Meta1
[Console]::Write("stderr:`n");
$r.Meta2
[Console]::Write("stdout:`n");
$r.Meta3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接