用UTF-8编码的tee命令

19
我尝试在PowerShell 4中将服务器的输出同时存储到控制台和文件中,但是文件以UTF-16编码结束,这与我使用的某些其他工具不兼容。根据"help tee -full"的说法:
Tee-Object在写入文件时使用Unicode编码。 ... 要指定编码,请使用Out-File cmdlet。
因此,"tee"不支持更改编码,而"tee"和"Out-File"的帮助文档都没有显示将流拆分并使用UTF-8编码的示例。
在Powershell 4中,有没有一种简单的方法可以使用UTF-8编码将流tee(或以其他方式拆分)到文件中?

5
默认使用UCS2(也称为UTF-16)而不是UTF8输出,这真是遗憾的事情... - bouvierr
5个回答

16

一个选项是使用 Add-ContentSet-Content 代替 Out-File

*-Content 命令默认使用 ASCII 编码,并具有 -Passthru 开关,因此您可以将内容写入文件,然后使输入通过到控制台:

Get-Childitem -Name | Set-Content file.txt -Passthru

无法追加...不一样。 - majkinetor
3
回答中提到了“Add-Content”,它是用于追加内容的。在忽略答案之前,请仔细阅读。 - Ansgar Wiechers
@AnsgarWiechers,“Add-Content”和“tee”不是一样的命令,试着在放弃答案之前都尝试一下:) “dir | Add-Content out1”与“dir | tee out2 -Append”相比。此外,它的语义不正确。人们使用tee来处理这样的东西,当你看到它时,就知道它应该做什么。 - majkinetor
2
没有人说它是一样的。虽然可以用于相同的目的。尝试使用 dir | Out-String | Add-Content out1 -PassThru - Ansgar Wiechers
2
这是目前最好的解决方案,虽然与tee不同,但它会锁定文件。 - Angus
显示剩余2条评论

7

您需要使用-Variable,然后在单独的步骤中将其写入文件。

$data = $null
Get-Process | Tee-Object -Variable data
$data | Out-File -Path $path -Encoding Utf8

乍一看,避免使用 tee 并将输出存储到变量中,然后将其写入屏幕和文件似乎更容易。但由于管道的工作方式,这种方法允许长时间运行的管道在进行时在屏幕上显示数据。不幸的是,对于文件来说情况并非如此,文件只有在之后才会被写入。

同时实现两者

另一种选择是自己编写一个类似于 tee 的程序:
[String]::Empty | Out-File -Path $path  # initialize the file since we're appending later
Get-Process | ForEach-Object {
    $_ | Out-File $path -Append -Encoding Utf
    $_
}

这将写入文件并返回到管道中,随着过程的进行而发生。但这可能会相当缓慢。


VariableAppend 在 tee 中无法同时使用。Out-File 是可以的解决方案,但需要使用函数,因为它没有 PassThru - majkinetor

5

Tee-object 似乎会调用 out-file,因此这将使 tee 的输出为 utf8:

$PSDefaultParameterValues = @{'Out-File:Encoding' = 'utf8'}

如何将其设置为强制全局默认值?以便我们可以在所有Windows服务器上部署。 - MortenB
1
@MortenB 请尝试将其放置在 $profile.AllUsersAllHosts 或 $profile.AllUsersCurrentHost 中。 - js2010

0

GitHub问题#11104中提到。

PowerShell 7.3.0或更高版本支持-Encoding参数,该参数可以使用以下之一:ASCIIBigEndianUnicodeOEMUnicodeUTF7UTF8UTF8BOMUTF8NoBOM(默认)和UTF32

NAME
    Tee-Object

SYNTAX
    Tee-Object [-FilePath] <string> [-InputObject <psobject>] [-Append] [-Encoding <Encoding>] [<CommonParameters>]

    Tee-Object -LiteralPath <string> [-InputObject <psobject>] [-Encoding <Encoding>] [<CommonParameters>]

    Tee-Object -Variable <string> [-InputObject <psobject>] [<CommonParameters>]


ALIASES
    tee


REMARKS
    Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
        -- To download and install Help files for the module that includes this cmdlet, use Update-Help.
        -- To view the Help topic for this cmdlet online, type: "Get-Help Tee-Object -Online" or
           go to https://go.microsoft.com/fwlink/?LinkID=2097034.

即使有那个标志,由于PowerShell解析管道输出的方式,可能仍然会出现乱码。请参阅#17523
引用: @jbobrean93:PowerShell依赖于System.Diagnostics.Process来解析管道输出,在启动信息中未显式设置Standard*Encoding属性时,它将依赖于全局设置的Console.OutputEncoding来确定使用的编码。在Windows上,默认的控制台编码仍然是操作系统配置的编码,通常是英文主机上的431。不幸的是,在这里您唯一的解决方法是设置[Console]::OutputEncoding = [System.Text.Encoding]::UTF8,然后运行您的命令。
使用的命令
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
YOUR_COMMAND_HERE | Tee-Object -FilePath YOUR_OUTPUT_FILE -Encoding UTF8NoBOM

注意事项

您可能希望更新您的PowerShell以使用此功能。请使用

$PSVersionTable

检查您的PowerShell版本。

-1

首先使用适当的标志创建文件,然后进行追加:

Set-Content  out $null -Encoding Unicode
...
cmd1 | tee out -Append
...
cmdn | tee out -Append

这是在文件中每个UTF8字符之间放置空字节。 - Angus
很奇怪。我检查了一下,使用UnicodeUTF7编码时并没有出现这种情况。 - majkinetor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接