求教, bat 脚本里,设了 chcp 仍然有中文无法正确显示

230 天前
 sugarsalt
从 stackoverflow 抄了一段用来使得特定行输出不一样颜色的 bat 脚本,但是用来输出中文文本会乱码
用了 chcp 65001 也不行
我的实验脚本如下
@echo off
SETLOCAL EnableDelayedExpansion
chcp 65001 >nul

for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
set "DEL=%%a"
)

set "text=什么"
echo %text%
call :ColorText 0c "%text%"
call :ColorText 0c "shen me"

pause

:ColorText
echo off
echo %DEL% > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1
goto :eof

echo 能正常显示“什么”,call :ColorText 0c "%text%"就不行

颜色代码来自前两个最高分回答
https://stackoverflow.com/questions/21660249/how-do-i-make-one-particular-line-of-a-batch-file-a-different-color-then-the-oth

我看不懂原本那个改颜色代码的原理,所以想请问一下大家有没有解决的办法?
谢谢
757 次点击
所在节点    程序员
6 条回复
geelaw
230 天前
这段代码相当糟糕,是利用 findstr 这个工具显示文件名,因此你传入的字符串必须是合法的文件名,而且显示的时候会覆盖当前目录下的同名文件——总之就是个不定时炸弹。

如果必须要用 batch ,推荐 https://gist.github.com/mlocati/fdabcaeb8071d5c75a2d51712db24011
否则可以考虑 PowerShell

另外请不要在 bat 里面 chcp ,这是在劫持用户的 console ,而且我没找到如何让 Windows 以固定的编码读取 batch 的功能,它或许永远是以系统代码页读取 batch 并运行的,也可能是按照当前代码页一次读取一行运行的。考虑如下 UTF-8 的 batch:

chcp 932>nul 2>nul
chcp 65001>nul 2>nul && echo ¿

其中 echo 的字符是 U+00BF ,它的 UTF-8 编码是 0xC2 0xBF ,一开始的 932 是 Windows 的 Shift JIS 实现,在这个代码页里 0xC2 不是合法的开头字节,因此在默认的日语 Windows 上执行它会产生不可预知的后果。

实际效果是打印出来的并不是倒转的问号,而是 ツソ 这两个符号。
geelaw
230 天前
至于原来的代码为什么不行,假设 batch 是 UTF-8 保存的,且本机代码页是 936 ,那么最终有颜色的输出结果是 "ʲô",这是把 "什么" 用 Windows-936 (~ GB) 编码之后再用 UTF-8 解码,这说明 cmd 设置变量的时候,是用 UTF-8 解读 batch 文件的(从而正确把文件中的字节解读为 "什么"),但是数据传入 findstr.exe 之后变成了 Windows-936 ,这很可能是因为 findstr.exe 使用的不是 WCHAR 而是 CHAR (因此 argv 是根据系统代码页,也就是 936 ,解读的,因此 findstr.exe 内部看到的是 GB 编码的 "什么"),并且在最后 findstr.exe 向控制台以输出了它所得到的字节流(即输出了 GB 编码的 "什么")——但控制台的代码页是 UTF-8 ,因此它把 GB 编码的 "什么" 用 UTF-8 解读并显示。
adoal
230 天前
还是不要尝试在 code page 时代的遗产软件上用 Unicode 了。天生的缺陷。
ysc3839
230 天前
@geelaw 那个 gist 的代码其实还能简化,可以直接 set ESC=然后后面复制一个 ESC 字符进去,不需要 for 啥的。
具体参见 https://github.com/Maximus5/ConEmu/blob/master/Release/ConEmu/SetEscChar.cmd
xiangyuecn
230 天前
太骚了,用 findstr 来显示不同颜色的文件名,输出些简单的标签文本还行,Log 、Warn 、Error

要通用,还是直接 bat 所在目录放一个可以输出不同颜色文本的 exe ( cmdcolor.exe 之类的),echo 换成这个 exe 就搞定了( findstr 命令本身就是 findstr.exe )
sugarsalt
229 天前
@geelaw #1 感谢解答!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/975893

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX