您自己Start-Process
的解决方案使用-RedirectStandardOutput
并-RedirectStandardError
确实创建(BOM-less)UTF-8 编码的输出文件,但请注意,它们也总是有一个尾随换行符。
但是,您不需要Start-Process
,因为您可以使 PowerShell 的重定向运算符也>
生成UTF-8 文件(也带有尾随换行符)。
以下示例使用cmd.exe
生成 stdout 和 stderr 输出的示例调用。
在PowerShell (Core) v6+中,不需要额外的工作,因为默认情况下>
会生成(无 BOM 的)UTF-8 文件 (一致使用的默认值;如果您想要带有 BOM 的UTF-8 ,您可以使用详细的技术对于下面的 Windows PowerShell,但具有值):'utf8bom'
cmd /c 'echo hü & dir c:\nosuch' 2>stderr.txt >stdout.txt
在Windows PowerShell中,>
默认生成 UTF-16LE ("Unicode"),但在 5.1 版中,您可以(暂时)使用 UTF-8 重新配置它,尽管总是使用 BOM;有关详细信息,请参阅此答案;另一个需要注意的是,文件中捕获的第一条 stderr 行将被格式化为“嘈杂”,就像 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
警告:
- 每当 PowerShell 处理外部程序的输出时,它总是首先将其解码为 .NET 字符串。假定任何外部程序都会根据存储在 中的字符编码生成输出
[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可以通过一个简单的变量 assignment来捕获,它将多个输出行捕获为字符串数组:
$stdout = cmd /c 'echo hü & dir c:\nosuch'
您不能单独捕获stderr输出,但您可以将stderr 合并到 stdout 中2>&1
,甚至稍后根据它们的数据类型再次分离流各自的输出行: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 原生命令(您甚至可以将PowerShell 支持的所有其他流合并到成功输出流中,PowerShell 模拟到标准输出,使用*>&1
)。
但是,如果给定的 PowerShell 原生命令是cmdlet /高级脚本或函数,则更方便的替代方法是使用common-OutVariable
参数(用于成功流输出)和common-ErrorVariable
参数(用于错误流输出)。