【问题标题】:Why does Powershell's Tee-Object mess up the encoding of my file?为什么 Powershell 的 Tee-Object 会弄乱我文件的编码?
【发布时间】:2021-09-17 00:47:24
【问题描述】:

我在周末使用 Tee-Object 生成了我正在跟踪的日志文件的一些输出,我尝试对输出文件进行 greping 操作,但无法返回任何结果。但我能够 grep 的原始日志文件。

好像Tee-Object改变了文件的编码。

https://adamtheautomator.com/tee-object-powershell/

是否有一个设置我可以更改为只吐出它开始读取的相同编码,并保持行尾相同?

【问题讨论】:

  • 遗憾的是,简短的回答是否定的 - Tee-Object 没有 -Encoding 参数,它不会在附加之前确定文件的编码,并且仅作为 unicode 输出。跨度>

标签: powershell


【解决方案1】:

简短回答不,没有-Encoding 参数。

来自 PowerShell Tee-Object 文档:

Tee-Object 在写入文件时使用 Unicode 编码。因此, 输出可能未在具有不同文件的文件中正确格式化 编码。要指定编码,请使用 Out-File cmdlet。

【讨论】:

  • 确实如此。注意 PowerShell Core 中的编码是(BOM-less)UTF-8,而不是“Unicode”(UTF-16LE),它仅适用于 Windows PowerShell。另外,let's try to fix this limitation
【解决方案2】:

作为一种解决方法,将 tee 设置为变量,然后使用 set-content 将其保存到文件中。默认编码为“ansi”。

echo hi | tee -Variable a
set-content file $a

这是一个示例,如果您想要像 out-file 通常提供的额外格式。我猜,因为原来的问题没有例子:

ps cmd | tee -var a
$a | out-string | set-content file

实际上,看起来 tee-object 正在调用 out-file,所以这会将 tee-object 的编码设置为 ascii:

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

【讨论】:

  • -Variable 解决方法原则上是有用的,但仅适用于 Out-File -Encoding,不适用于 Set-Content,因为它不会像 Tee-ObjectOut-File 那样格式化对象- 试试$PSVersionTable | Set-Content t.txt,例如。通过Out-File 很好地找到了默认参数解决方法,但是以command-scoped 方式进行这项工作(在剩余的会话中没有影响)在实践中太麻烦了。但是,很高兴知道会话中存在这样的默认参数值确实会影响Tee-Object 的行为。
  • @mklement0 如果你想要额外的格式,在 tee -variable 之前通过管道输出字符串
  • 如果您的意图是为Tee-Object 提供一种解决方法,它总是使用 PowerShell 的输出格式系统,Set-Content 不够用,因为它使用.ToString() 格式。因此,正确的解决方法是使用$a | Out-File file -Encoding $yourEncoding。是的,您可以使用$a | Out-String | Set-Content -Encoding $yourEncoding,但这显然效率更低且更麻烦。
  • 顺便说一句,对于 PowerShell Core 用户:tee 在类 Unix 平台上不能用作别名,其中 tee 指的是本机 @987654339 @ 效用)。 ANSI 编码是Set-Content 的默认值,仅在 Windows PowerShell 中;在 PowerShell Core 中,它是(无 BOM 的)UTF-8。
  • 由于 tee-object 提供 -Append 问题变得更加复杂,因为 tee 可能只是附加到文件的众多进程之一。如果是这种情况,那么文件(我的测试显示)将是 UTF8 和 UTF16 的组合。如果发生这些情况,那么使用 out-file 或其他任何方法来纠正问题将不起作用。出现此问题后,只有过滤掉 NULL 才能解决问题。如果 tee-object 提供 -Encoding 选项会更好。简而言之,如果 tee -Append 将 UTF16 写入已经是 UTF8 的文件的末尾,那么你就完蛋了!
【解决方案3】:
  • HAL's helpful answer 表明,从 Windows PowerShell 5.1 / PowerShell Core 7.0.0-preview.5 开始,Tee-Object 在输出到文件时不支持明确指定输出编码,而是总是在 Windows PowerShell 中使用“Unicode”(UTF-16LE) 编码,在 PowerShell Core 中使用(BOM-less) UTF-8

    • This GitHub feature request 建议通过将-Encoding 参数添加到Tee-Object 来消除此限制,以允许指定所需的输出编码。

    • js2010's answer 表明实际上存在一种间接 方法来控制编码,通过默认参数值表$PSDefaultParameterValues 中针对Out-File 的条目(例如,@987654329 @)。

      • 但是,Tee-ObjectOut-File 之间的这种意外耦合不应该存在,甚至可能被删除 - 最好不要依赖它。 (此外,将其范围限定为Tee-Objectindividual 调用并非易事。
  • js2010 的答案也是一个很好的解决方法,首先是 变量,但 Set-Content 不是用于保存捕获的对象的正确 cmdlet ,因为它对其输入执行简单的 .ToString() 字符串化,而 Tee-Object - 像 Out-File - 应用 PowerShell 丰富的默认格式。

因此,请考虑以下解决方法

# Tee to a *variable* first ($out)...
$PSVersionTable | Tee-Object -Variable out # | ...

# ... then use Out-File -Encoding to save to a file with the desired encoding
# ; e.g., with UTF-8
Out-File -InputObject $out out.txt -Encoding utf8

至于:

有没有我可以更改的设置以输出相同的编码

否 - PowerShell 通常不支持:它将文件内容读入内存中的 .NET 字符串,并在保存回文件时应用默认(或指定)字符编码。

唯一的解决方法是手动确定输入文件的编码,然后将该编码的名称传递给具有-Encoding 参数的写入文件cmdlet,例如Out-File
Set-Content

【讨论】:

    【解决方案4】:

    如前所述,tee 命令没有encoding 选项。为了解决这个问题,我可以使用以下方法进行转换:

    <powershell command> | tee -Variable content
    $content | Set-Content -Encoding uft8 test_output.txt
    

    这比我尝试使用 Out-File 所做的测试效果更好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-13
      • 1970-01-01
      • 2021-03-08
      • 2012-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多