【问题标题】:Batch variable being set to ■1 instead of intended output批处理变量设置为 ■1 而不是预期的输出
【发布时间】:2018-08-02 23:17:04
【问题描述】:

我正在编写一个脚本,需要将文件的内容作为设置变量的输入。我正在使用 Out-File 生成一个文本文件:

$string | Out-File -FilePath C:\Full\Path\To\file.txt -NoNewLine

然后我正在使用该文件批量设置变量:

set /P variablename=<C:\Full\Path\To\file.txt

该文件的内容是一个唯一的 id 字符串,实际上看起来像这样:

1i32l54bl5b2hlthtl098

当我回显这个变量时,我得到了这个:

echo %variablename%
■1

当我在输入文件中尝试了不同的字符串时,我看到回显的是 ■ 字符,然后是字符串中的第一个字符。所以,如果我的字符串是“apfvuu244ty0vh”,那么它会回显“■a”。

为什么没有将变量设置为文件的内容?我正在使用来自this stackoverflow post 的方法,其中选择的答案说要将此语法与 set 命令一起使用。难道我做错了什么?使用完整路径作为集合变量的输入是否存在问题?

【问题讨论】:

  • 我会假设文件没有保存为 ASCII 文本。它很可能是某种形式的带有 BOM 的 unicode。
  • Notepad++ 告诉我它被编码为 UCS-2 LE BOM。该文件由 Powershell 中的 Out-File 生成,因此我将探索我拥有的任何编码选项并进行报告。
  • 是的。你可以告诉Powershell to output the file as ascii。请看一下 Powershell 代码。
  • 做到了。非常感谢,我已经添加了 powershell 信息(应该添加到一起)。你能给出关于编码的答案以便我接受吗?

标签: windows powershell batch-file


【解决方案1】:

tl;dr

使用Out-File -Encoding oem 生成cmd.exe 可以正确读取的文件。

这实际上将您限制为旧版“ANSI”/OEM 代码页中可用的 256 个字符,NUL (0x0) 除外。如果您需要完整的 Unicode 支持,请参阅底部部分。


Windows PowerShell(但不是 PowerShell Core)中,Out-File 及其有效别名 &gt; 默认为 UTF-16LE character encoding其中大多数字符表示为 2 字节序列;对于 ASCII 范围内的字符,每个序列的第 2 个字节是 NUL (0x0);此外,此类文件以 BOM 开头,指示编码类型

相比之下,cmd.exe 期望输入使用传统的单字节 OEM 编码(请注意,以 /U 开头的 cmd.exe 仅控制其输出的编码 em>)。

cmd.exe(它不知道)遇到 UTF-16LE 输入时:

  • 它将字节单独解释为字符(即使 UTF-16LE 中的字符通常由 2 个字节组成,或者在极少数情况下由 4 个字节组成(一对 2 -字节序列))。

  • 它将构成 BOM 的 2 个字节(0xff0xfe解释为字符串的一部分。在 OEM code page 437(美国英语)生效时,0xff 呈现为 空格,而 0xfe 呈现为

  • 一旦遇到第一个 NUL0x0 字节),读取就会停止,这发生在 ASCII 范围的第一个字符上,在您的示例字符串中是 1

    李>

因此,正如您所说,编码为 UTF-16LE 的字符串 1i32l54bl5b2hlthtl098 被读取为  ■1


如果您需要完整的 Unicode 支持,请使用UTF-8 编码:

  • 在 PowerShell 中使用 Out-File -Encoding utf8

  • 在读取cmd.exe 中的文件(在批处理文件中)之前,运行chcp 65001 以切换到UTF-8 code page

注意事项:

  • 并非所有 Unicode 字符。可能渲染正确,具体取决于控制台窗口中使用的字体。

  • 旧版应用程序可能会因代码页 65001 生效而出现故障,尤其是在较旧的 Windows 版本上。

    • 避免问题的一种可能策略是暂时根据需要切换到代码页65001,然后再切换回来。

请注意,以上仅涵盖通过文件进行的通信,并且仅在一个方向(PowerShell -> cmd.exe)。
也可以控制用于标准流(stdin、stdout、stderr)的字符编码,无论是在向 cmd.exe / 外部程序发送字符串时还是在解释从它们接收到的字符串时,参见this answer 我的。

【讨论】:

  • 伟大而翔实的答案。我使用了 Squashman 在评论中建议的 Out-File -Encoding ASCII,这对我有用,但我相信我将来会回到这个答案。谢谢。
  • @OilyBusiness:很高兴听到它有帮助; -Enocding ASCII 工作正常,只要您只使用 7 位 ASCII 范围内的字符,但如果您有重音字符(例如 ï),它们将被替换为 literal i> ? - 也就是说,你会丢失信息。 -Encoding oem 将支持扩展到基于旧系统区域设置的有效代码页(“ANSI”/OEM),因此您将获得对另外 128 个字符的支持。 (8 位范围),包括一些重音字符。如前所述,完整的 Unicode 支持需要更改代码页。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2012-07-07
  • 2014-10-10
  • 2011-09-15
相关资源
最近更新 更多