【问题标题】:Powershell Encoding Default OutputPowershell 编码默认输出
【发布时间】:2018-07-08 05:16:40
【问题描述】:

我在 TFS 构建中运行的 powershell 脚本存在以下问题。这两个问题都与 TFS 无关,可以使用简单的 powershell 命令行窗口重现。

1) 与 TFS 完全无关。在管道方面,Powershell 似乎不喜欢德国变音符号。

1a) 这行代码工作正常,所有变音符号都正确显示

.\TF.exe hist "$/Test" /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /version:C1~T

1b) 这条线与变音符号混在一起

.\TF.exe hist "$/Test" /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /version:C1~T | Out-String

最初我尝试了 Out-File 并将编码更改为每个排版(UTF8、unicode、UTF32、...)中的元音变音编码错误

我真的不知道如何从标准输出中提取字符串并正确使用变音符号。

2) 当使用 Out-File 或 Out-String 时,输出中的每一行在 80 个字符后被截断,这似乎是默认的屏幕缓冲区设置。如何在 powershell 脚本中更改它,为什么它甚至在重定向输出时会产生影响。

【问题讨论】:

  • “变音变音”:请告诉我们,否则我们只是在猜测。另请注意tf.exe 不是 PowerShell 的一部分,它只是一个 Windows 控制台可执行文件:您可能需要了解它如何对其输出进行编码才能成功读取它。

标签: powershell encoding tfs


【解决方案1】:

问题 2 不是 Powershell 问题。 tfs documentation 表示默认/format 参数(即/format:brief

部分数据可能会被截断。

/format:detailed 没有该警告,但它会返回更多信息,您可以在执行 Out-StringOut-File 之前使用 Powershell 处理这些信息。

【讨论】:

    【解决方案2】:

    tl;dr

    以下内容应该可以解决您的两个问题,这些问题源于 tf.exe 使用 ANSI 字符编码而不是预期的 OEM 编码,以及默认情况下截断输出。:

    • 如果您使用的是 Windows PowerShell(仅限 Windows 的旧版 PowerShell,版本最高为 v5.1):
    $correctlyCapturedOutput = 
      & {
        $prev = [Console]::OutputEncoding
        [Console]::OutputEncoding = [System.Text.Encoding]::Default
    
        # Note the addition of /format:detailed
        .\tf.exe hist '$/Test' /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /format:detailed /version:C1~T
    
        [Console]::OutputEncoding = $prev
      }
    
    • 如果您使用跨平台,按需安装PowerShell (Core) 7+

      • 注意:[System.Text.Encoding]::Default,它在 Windows PowerShell 中报告活动 ANSI 代码页的编码,在 PowerShell (Core) 中报告(无 BOM)UTF-8(反映 .NET Core 的 / .NET 5+ 的行为)。因此,必须明确确定活动的 ANSI 代码页,这通过注册表最可靠地完成。
    $correctlyCapturedOutput = 
      & {
        $prev = [Console]::OutputEncoding
        [Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding(
          [int] ((Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Nls\CodePage ACP).ACP)
        )
    
        # Note the addition of /format:detailed
        .\tf.exe hist '$/Test' /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /format:detailed /version:C1~T
    
        [Console]::OutputEncoding = $prev
      }
    

    This Gist包含辅助函数Invoke-WithEncoding,可以在两个PowerShell版本中将上述简化如下:

    $correctlyCapturedOutput = 
      Invoke-WithEncoding -Encoding Ansi {
        .\tf.exe hist '$/Test' /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /format:detailed /version:C1~T
      }
    

    您可以直接下载并使用以下命令定义函数(虽然我个人可以向您保证这样做是安全的,但最好先检查源代码):

    # Downloads and defines function Invoke-WithEncoding in the current session.
    irm https://gist.github.com/mklement0/ef57aea441ea8bd43387a7d7edfc6c19/raw/Invoke-WithEncoding.ps1 | iex
    

    继续阅读以了解详细讨论。


    关于元音变音(字符编码)问题:

    虽然外部程序的输出可能打印控制台,但当涉及到在变量中捕获输出或重定向时 - 例如在您的情况下通过管道将其发送到 Out-String - PowerShell 使用存储在 @987654337 中的字符编码将输出解码为 .NET 字符串 @

    如果[Console]::OutputEncoding 与外部程序使用的实际编码不匹配,PowerShell 将误解输出。

    解决方案是(临时)将[Console]::OutputEncoding 设置为外部程序使用的实际编码

    虽然official tf.exe documentation 未讨论字符编码,但此comment on GitHub 表明tf.exe 使用系统的活动ANSI 代码页,例如美国英语或西欧系统上的Windows-1252。

    应该注意ANSI代码页的使用对于控制台应用程序来说是非标准行为 ,因为控制台应用程序应使用系统的活动 OEM 代码页。顺便说一句:python 默认情况下也表现出这种非标准行为,尽管它的行为是可配置的。

    顶部的解决方案显示了如何将[Console]::OutputEncoding 临时切换到活动的 ANSI 代码页的编码,以确保 PowerShell 正确解码 tf.exe 的输出。


    Out-String / Out-File 重新截断输出行(因此还有>>>):

    • 正如Mustafa Zengin's helpful answer 指出的那样,在您的特定情况下-由于使用tf.exe-截断发生在,即tf.exe本身按照其默认格式输出截断的数据(当还指定了/noprompt 时,隐含/format:brief)。

    • 一般来说,Out-StringOut-File / > / >> 会根据控制台窗口宽度按情况截断或换行它们的输出行 strong>(默认为120 字符。在没有控制台的情况下):

      • 换行的截断仅适用于由 PowerShell 丰富的输出格式系统生成的非原始、非字符串对象表示的输出行:

      • 字符串本身[string] 输入)以及 .NET 原始类型的字符串表示形式(加上更多的单值类型) em>不会被截断/换行。

    • 由于 PowerShell 只将 外部程序 的输出解释为 文本[string] 实例),所以截断/换行 em> 发生

      • 因此通常没有理由在外部程序输出上使用Out-String - 除非您需要加入输出行的流(数组)以形成一个单个多行 用于进一步内存处理的字符串。
      • 但是,请注意,Out-String总是在结果字符串中添加一个尾随换行,这可能是不受欢迎的;使用(...) -join [Environment]::NewLine 来避免这种情况; Out-String 的问题行为在GitHub issue #14444 中进行了讨论。

    【讨论】:

      猜你喜欢
      • 2017-02-27
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多