如何在cmd.exe上进行正确的Unicode和ANSI输出重定向?

9
如果您正在Windows上进行自动化,并且正在重定向不同命令的输出(内部cmd.exe或外部),则会发现日志文件包含合并的Unicode和ANSI输出(这意味着它们无效,将无法在查看器/编辑器中加载)。是否可以使cmd.exe与UTF-8一起使用?这个问题不涉及显示,而是关于stdin/stdout/stderr重定向和Unicode。我正在寻找一个解决方案,可以让您执行以下操作:1. 使用UTF-8将内部命令的输出重定向到文件;2. 将支持Unicode的外部命令的输出重定向到文件,但编码为UTF-8。如果使用批处理文件无法获得此类一致性,则还有其他解决此问题的方法吗?比如使用python脚本?在这种情况下,我想知道是否可能仅对Unicode进行检测 (使用脚本的用户不需要记住调用的工具是否会输出Unicode,它只会期望将输出转换为UTF-8)。出于简单起见,我们假设如果工具输出不是Unicode,则将其视为UTF-8(无代码页转换)。
2个回答

10
你可以使用chcp来更改活动的代码页,这也将用于重定向文本:
chcp 65001

需要注意的是,如果cmd是通过强制Unicode(在这种情况下是UTF-16)重定向输出的/u开关启动的,则此操作将无效。如果该开关处于激活状态,则所有输出都将为UTF-16LE,而不管使用chcp设置的代码页。

另请注意,当设置为点阵字体时,控制台将无法用于交互式输出。在这种情况下,我会收到有趣的错误消息:

C:\Users\Johannes Rössel\Documents>x
Active code page: 65001

The system cannot write to the specified device.

因此,要么使用合理的设置(控制台采用 TrueType 字体),要么在交互式使用控制台并且路径包含非 ASCII 字符时不要拉这种花招。


如果你再做一些研究,你会发现在任何版本的Windows上都不支持UTF-8代码页。因此,“chcp 65001”没有意义。 - sorin
@Sorin:它确实可以工作,但不可靠也没有支持。如果您有UTF编码的批处理文件要运行(没有BOM),则可以使用此方法。 - Joey
在使用UTF-8作为ANSI代码页时存在一个重大错误,即WriteFile() API返回写入的代码点数,而不是文档中记录的写入的字节数。这个API最终被大多数C库函数(如printf())和大多数脚本语言(包括Perl、PHP和Ruby)调用。任何检查写入是否成功的代码,通过比较发送的字节数和返回的字节数将失败。使用返回的数字移动输出光标的代码将导致打印非ASCII文本时出现乱码。 - hippietrail
就像Joey所说的那样,它是不一致和不可靠的。例如,我刚试图将一个PowerShell脚本(从cmd运行)的输出重定向到文本文件。它一直输出ANSI,因此任何非ASCII字符都是不正确的。我使用了chcp 65001来更改代码页,然后文本文件包含了正确的Unicode字符。然而,当我创建了一个UTF-8批处理文件,其中只有一个简单的echo ‽,它在代码页437下显示不正确,在65001下则根本没有显示。将其重定向到文件时,在代码页65001下没有输出,在代码页437下则有正确的输出。ಠ_ఠ - Synetech
@Synetech:对于CP437来说,应该期望得到正确的输出。在这种情况下,CMD只是写入批处理文件中完全相同的字节。它并不关心它实际上可以解释为UTF-8。 - Joey

0
binmode(STDOUT, ":unix");

不用

use encoding 'utf8';

帮了我。因为我在打印时收到了“宽字符”的警告。


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