我试图将命令的 stdout 和 stderr 输出存储到两个单独的文件中。我这样做是这样的:
powershell.exe @_cmd 2>"stderr.txt" >"stdout.txt"
其中
$_cmd
是任意字符串命令。
这可行,但输出文件在输出后附加了换行符。我想修改它以消除换行符。我知道您可以使用
cmd | Out-File ... -NoNewline
或 [System.IO.File]::WriteAllText(..., [System.Text.Encoding]::ASCII)
,但我不确定如何使用 stderr 输出来完成此操作。
编辑:我意识到问题不是特别是尾随新行(尽管我仍然想删除它),而是我需要输出文件采用 UTF-8 编码这一事实。尾随的新行显然不是有效的 UTF-8 字符,这让我感到悲伤。也许有一种方法可以捕获stderr和stdout来分离变量,然后使用
Out-File -Encoding utf8
?
Start-Process
的解决方案使用-RedirectStandardOutput
和-RedirectStandardError
确实创建了(无BOM)UTF-8编码的输出文件,但请注意,它们也总是有一个尾随换行。
但是,您不需要需要
Start-Process
,因为您可以使PowerShell的重定向运算符、>
也生成UTF-8文件(也带有尾随换行符)。
以下示例使用示例
cmd.exe
调用,该调用会生成 stdout 和 stderr 输出。
在 PowerShell (Core) 7中,不需要额外的努力,因为
>
会生成(无 BOM)UTF-8 文件 默认情况下(一致使用的默认值;如果如果您想要 UTF-8 with BOM,您可以使用 Windows PowerShell 详细介绍的技术下面,但有价值 'utf8bom'
):
cmd /c 'echo hü & dir c:\nosuch' 2>stderr.txt >stdout.txt
在 Windows PowerShell中,
>
默认生成 UTF-16LE(“Unicode”),但在版本 5.1中,您可以(暂时)重新配置它使用 UTF-8,尽管总是使用 UTF-8 带有 BOM;有关详细信息,请参阅此答案;另一个需要注意的是,文件中捕获的 first stderr 行将被格式化为“noisily”,就像 PowerShell 错误一样:
# Windows PowerShell v5.1:
# Make `>` and its effective alias, Out-File, use UTF-8 with a BOM in the
# remainder of the session.
# Save and restore any previous value if you want to scope the behavior
# to select commands only.
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
cmd /c 'echo hü & dir c:\nosuch' 2>stderr.txt >stdout.txt
警告:
[Console]::OutputEncoding
中存储的字符编码生成输出,该编码默认为系统的活动 OEM 代码页。这与 cmd.exe
的工作方式一致,但还有其他控制台应用程序使用不同的编码 - 特别是 node.exe
(Node.js) 和 python
,它们分别使用 UTF-8 和系统的活动 ANSI 代码页- 在这种情况下,必须首先将 [Console]::OutputEncoding
设置为该编码;请参阅此答案了解更多信息。至于您的陈述和问题:
尾随的新行显然不是有效的 UTF-8 字符
PowerShell 的
>
运算符和文件输出 cmdlet 一致应用其字符编码,因此尾随换行符的编码始终与文件中其他字符的编码一致。
最有可能的是 Windows PowerShell 默认使用的 UTF-16LE(“Unicode”)编码才是真正的问题,您可能只注意到换行符。
也许有一种方法可以捕获 stderr 和 stdout 以分隔变量
Stdout 可以通过简单的变量赋值来捕获,它将多个输出行捕获为字符串的数组:
$stdout = cmd /c 'echo hü & dir c:\nosuch'
您无法单独捕获stderr输出,但您可以使用2>&1
将stderr
合并到stdout,甚至稍后根据数据类型再次分离流各自的输出行:stdout行始终是 strings,而 stderr 行始终是
[ErrorRecord]
实例:
# Note the 2>&1 redirection.
$stdoutAndErr = cmd /c 'echo hü & dir c:\nosuch' 2>&1
# If desired, you can split the captured output into stdout and stderr output.
# The [string[]] cast converts the [ErrorRecord] instances to strings too.
$stdout, [string[]] $stderr = $stdoutAndErr.Where({ $_ -is [string] }, 'Split')
# Now $stdout is the array of stdout lines, and $stderr the array of stderr lines.
# If desired, you could write them to files *without a trailing newline* as follows:
$stdout -join [Environment]::NewLine | Set-Content -NoNewLine -Encoding utf8 stdout.txt
$stderr -join [Environment]::NewLine | Set-Content -NoNewLine -Encoding utf8 stderr.txt
您还可以将这些技术应用于 PowerShell-native 命令(您甚至可以将 PowerShell 支持的所有其他流合并到成功输出流中,PowerShell 类似于 stdout,带有 *>&1
)。但是,
如果给定的 PowerShell 原生命令是 cmdlet / 高级脚本或函数,更方便的替代方案是使用 常用 -OutVariable
-ErrorVariable
参数(用于错误流输出)。
$process = Start-Process powershell.exe -ArgumentList "$_cmd" -Wait -PassThru -NoNewWindow -RedirectStandardError "stderr.txt" -RedirectStandardOutput "stdout.txt"
$exitcode = $process.ExitCode