【发布时间】:2012-01-19 11:32:57
【问题描述】:
我需要将多个进程的标准输出和错误日志收集到一个日志文件中。
所以每个输出都必须追加到这个日志文件。
我想用这样的行来调用所有作业:
$p=start-process myjob.bat -redirectstandardoutput $logfile -redirecterroroutput $logfile -wait
我必须将要附加的信息放在哪里?
【问题讨论】:
我需要将多个进程的标准输出和错误日志收集到一个日志文件中。
所以每个输出都必须追加到这个日志文件。
我想用这样的行来调用所有作业:
$p=start-process myjob.bat -redirectstandardoutput $logfile -redirecterroroutput $logfile -wait
我必须将要附加的信息放在哪里?
【问题讨论】:
为了附加到文件,您需要使用稍微不同的方法。您仍然可以将单个进程的标准错误和标准输出重定向到文件,但要将其附加到文件中,您需要执行以下操作之一:
Start-Process创建的stdout/stderr文件内容
&
第一种方式如下所示:
$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
【讨论】:
2>&1 | Out-File $file -Append -Encoding UTF8 是重定向 stdout 和 stderr 和使用 UTF-8 输出的唯一方法。
与 Unix shell 一样,PowerShell 支持 > 重定向以及 Unix 已知的大多数变体,包括 2>&1(尽管奇怪的是,顺序并不重要 - 2>&1 > file 的工作方式与普通的 > file 2>&1 一样)。
与大多数现代 Unix shell 一样,PowerShell 也有一个用于将标准错误和标准输出重定向到同一设备的快捷方式,但与其他几乎遵循 Unix 约定的重定向快捷方式不同,捕获所有快捷方式使用新的 sigil并且是这样写的:*>.
所以你的实现可能是:
& myjob.bat *>> $logfile
【讨论】:
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-transcript 和stop-transcript,您可以将PowerShell 命令的所有输出重定向到单个文件,但it doesn't work correctly with external commands。因此,让我们将这些输出的所有输出重定向到 PS 的标准输出,然后让脚本完成剩下的工作。
事实上,我不知道为什么 MS 工程师说“由于涉及的高成本和技术复杂性”他们还没有解决这个问题,因为它可以以如此简单的方式解决。
无论哪种方式,恕我直言,使用start-process 运行每一个命令是一个巨大的混乱,但使用这种方法,您所要做的就是将2>&1 | Write-Output 代码附加到运行外部命令的每一行。
【讨论】:
也许它不是那么优雅,但以下也可能有效。我怀疑异步这不是一个好的解决方案。
$p = Start-Process myjob.bat -redirectstandardoutput $logtempfile -redirecterroroutput $logtempfile -wait
add-content $logfile (get-content $logtempfile)
【讨论】: