Powershell:stdout 和 stderr 分隔文件,没有新行

Powershell: stdout and stderr to separate files, without new lines

我正在尝试将命令的 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?

@TheMadTechnician 的评论给出了有效的答案。

$process = Start-Process powershell.exe -ArgumentList "$_cmd" -Wait -PassThru -NoNewWindow -RedirectStandardError "stderr.txt" -RedirectStandardOutput "stdout.txt"
$exitcode = $process.ExitCode

您自己的 Start-Process-based 使用 -RedirectStandardOutput-RedirectStandardError 确实创建了 (BOM- less)UTF-8 编码的输出文件,但请注意它们也总是有一个尾随换行符

但是,不需要 Start-Process,因为 您可以使 PowerShell 的 redirection operator, > 也生成 UTF-8 文件(也带有尾随换行符).

以下示例使用生成 std​​out 和 stderr 输出的示例 cmd.exe 调用。

  • PowerShell (Core) v6+中,不需要额外的努力,因为> 生成(无 BOM)UTF-8 文件 默认(一致使用的默认值;如果你想要 UTF-8 对于 BOM,您可以使用下面针对 Windows PowerShell 详述的技术,但值 'utf8bom'):

    cmd /c 'echo hü & dir c:\nosuch' 2>stderr.txt >stdout.txt
    
  • WindowsPowerShell中,>产生UTF -16LE(“Unicode”)默认,但是在5.1版中你可以(暂时)重新配置它使用UTF-8代替,尽管总是有物料清单;详情见 ;另一个警告是文件中捕获的 first 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 设置为该编码;有关详细信息,请参阅

至于你的说法和问题:

The trailing new line is not a valid UTF-8 character apparently

PowerShell 的 > 运算符和文件输出 cmdlet 应用它们的字符编码一致,因此尾随换行符的编码始终与文件中其他字符的编码一致.

最有可能的是 Windows PowerShell 默认使用的 UTF-16LE(“Unicode”)编码才是真正的问题,您可能只注意到换行符。

Perhaps there's a way to capture the stderr and stdout to separate variables

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 命令(您甚至可以合并 all PowerShell 支持的其他流进入成功输出流,PowerShell 模拟标准输出,*>&1).

但是,如果给定的 PowerShell 本机命令是 cmdlet / 高级 脚本或函数更方便的选择是使用common -OutVariable parameter (for success-stream output) and common -ErrorVariable parameter(用于错误流输出)。