【问题标题】:Redirection of standard and error output appending to the same log file重定向附加到同一日志文件的标准和错误输出
【发布时间】:2012-01-19 11:32:57
【问题描述】:

我需要将多个进程的标准输出和错误日志收集到一个日志文件中。

所以每个输出都必须追加到这个日志文件。

我想用这样的行来调用所有作业:

$p=start-process myjob.bat -redirectstandardoutput $logfile -redirecterroroutput $logfile -wait

我必须将要附加的信息放在哪里?

【问题讨论】:

    标签: powershell powershell-2.0


    【解决方案1】:

    为了附加到文件,您需要使用稍微不同的方法。您仍然可以将单个进程的标准错误和标准输出重定向到文件,但要将其附加到文件中,您需要执行以下操作之一:

    1. 读取Start-Process创建的stdout/stderr文件内容
    2. 不使用 Start-Process 并使用 the call operator, &
    3. 不使用 Start-Process 并使用 .NET 对象启动进程

    第一种方式如下所示:

    $myLog = "C:\File.log"
    $stdErrLog = "C:\stderr.log"
    $stdOutLog = "C:\stdout.log"
    Start-Process -File myjob.bat -RedirectStandardOutput $stdOutLog -RedirectStandardError $stdErrLog -wait
    Get-Content $stdErrLog, $stdOutLog | Out-File $myLog -Append
    

    第二种方式如下所示:

    & myjob.bat 2>&1 >> C:\MyLog.txt
    

    或者这个:

    & myjob.bat 2>&1 | Out-File C:\MyLog.txt -Append
    

    第三种方式:

    $pinfo = New-Object System.Diagnostics.ProcessStartInfo
    $pinfo.FileName = "myjob.bat"
    $pinfo.RedirectStandardError = $true
    $pinfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $pinfo.Arguments = ""
    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $pinfo
    $p.Start() | Out-Null
    $p.WaitForExit()
    $output = $p.StandardOutput.ReadToEnd()
    $output += $p.StandardError.ReadToEnd()
    $output | Out-File $myLog -Append
    

    【讨论】:

    • 它是否适用于 Powershell 远程处理?我有测试,我认为只有第二种方式适用于 PS Remoting。
    • 第三种方式在某些情况下会导致死锁,请阅读MSDN或在此处讨论stackoverflow.com/a/8762068/151641
    • 太棒了! 2>&1 | Out-File $file -Append -Encoding UTF8 是重定向 stdout 和 stderr 使用 UTF-8 输出的唯一方法。
    【解决方案2】:

    与 Unix shell 一样,PowerShell 支持 > 重定向以及 Unix 已知的大多数变体,包括 2>&1(尽管奇怪的是,顺序并不重要 - 2>&1 > file 的工作方式与普通的 > file 2>&1 一样)。

    与大多数现代 Unix shell 一样,PowerShell 也有一个用于将标准错误和标准输出重定向到同一设备的快捷方式,但与其他几乎遵循 Unix 约定的重定向快捷方式不同,捕获所有快捷方式使用新的 sigil并且是这样写的:*>.

    所以你的实现可能是:

    & myjob.bat *>> $logfile
    

    【讨论】:

      【解决方案3】:

      Andy 给了我一些很好的建议,但我想以一种更简洁的方式来做。更不用说使用2>&1 >> 方法PowerShell 向我抱怨另一个进程正在访问日志文件,即我猜stderr 和stdout 都试图锁定文件以进行访问。所以这就是我的工作方式。

      首先让我们生成一个漂亮的文件名,但这真的只是为了迂腐:

      $name = "sync_common"
      $currdate = get-date -f yyyy-MM-dd
      $logfile = "c:\scripts\$name\log\$name-$currdate.txt"
      

      这就是诀窍开始的地方:

      start-transcript -append -path $logfile
      
      write-output "starting sync"
      robocopy /mir /copyall S:\common \\10.0.0.2\common 2>&1 | Write-Output
      some_other.exe /exeparams 2>&1 | Write-Output
      ...
      write-output "ending sync"
      
      stop-transcript
      

      使用start-transcriptstop-transcript,您可以将PowerShell 命令的所有输出重定向到单个文件,但it doesn't work correctly with external commands。因此,让我们将这些输出的所有输出重定向到 PS 的标准输出,然后让脚本完成剩下的工作。

      事实上,我不知道为什么 MS 工程师说“由于涉及的高成本和技术复杂性”他们还没有解决这个问题,因为它可以以如此简单的方式解决。

      无论哪种方式,恕我直言,使用start-process 运行每一个命令是一个巨大的混乱,但使用这种方法,您所要做的就是将2>&1 | Write-Output 代码附加到运行外部命令的每一行。

      【讨论】:

      • 因为不能,这完全取决于你调用的程序是做什么的。在这种情况下,“robocopy”有效,但并非对所有事情都是如此。
      【解决方案4】:

      也许它不是那么优雅,但以下也可能有效。我怀疑异步这不是一个好的解决方案。

      $p = Start-Process myjob.bat -redirectstandardoutput $logtempfile -redirecterroroutput $logtempfile -wait
      add-content $logfile (get-content $logtempfile)
      

      【讨论】:

      • 它实际上不起作用,因为 Powershell 不允许您将standardouput 和redirecterroroutput 重定向到同一个文件。 “启动进程:此命令无法运行,因为“RedirectStandardOutput”和“RedirectStandardError”相同。提供不同的输入并再次运行您的命令。”是我尝试这个时遇到的错误。
      • 我认为海报的意思是使用 $logFile 进行 -redirectstandardoutput。 exe 将写入这两个文件,然后第二行将一个文件附加到另一个文件。那会奏效。但是,它不会整理线条;只是附加。通常,exe 仅在运行结束时写入 err,因此通常可以正常工作。但不是一般情况。
      猜你喜欢
      • 2018-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多