V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sugarsalt
V2EX  ›  程序员

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

  •  
  •   sugarsalt · 2023-09-21 15:17:29 +08:00 · 966 次点击
    这是一个创建于 430 天前的主题,其中的信息可能已经有所发展或是发生改变。
    从 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

    我看不懂原本那个改颜色代码的原理,所以想请问一下大家有没有解决的办法?
    谢谢
    6 条回复    2023-09-22 04:51:17 +08:00
    geelaw
        1
    geelaw  
       2023-09-21 16:38:15 +08:00   ❤️ 2
    这段代码相当糟糕,是利用 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
        2
    geelaw  
       2023-09-21 17:17:00 +08:00
    至于原来的代码为什么不行,假设 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
        3
    adoal  
       2023-09-21 17:21:19 +08:00
    还是不要尝试在 code page 时代的遗产软件上用 Unicode 了。天生的缺陷。
    ysc3839
        4
    ysc3839  
       2023-09-21 18:02:57 +08:00 via Android
    @geelaw 那个 gist 的代码其实还能简化,可以直接 set ESC=然后后面复制一个 ESC 字符进去,不需要 for 啥的。
    具体参见 https://github.com/Maximus5/ConEmu/blob/master/Release/ConEmu/SetEscChar.cmd
    xiangyuecn
        5
    xiangyuecn  
       2023-09-21 19:50:42 +08:00
    太骚了,用 findstr 来显示不同颜色的文件名,输出些简单的标签文本还行,Log 、Warn 、Error

    要通用,还是直接 bat 所在目录放一个可以输出不同颜色文本的 exe ( cmdcolor.exe 之类的),echo 换成这个 exe 就搞定了( findstr 命令本身就是 findstr.exe )
    sugarsalt
        6
    sugarsalt  
    OP
       2023-09-22 04:51:17 +08:00
    @geelaw #1 感谢解答!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1355 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 17:25 · PVG 01:25 · LAX 09:25 · JFK 12:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.