【问题标题】:Batch file encoding批处理文件编码
【发布时间】:2022-05-11 14:54:21
【问题描述】:

我想处理包含奇怪字符的文件名,例如法语 é。

在 shell 中一切正常:

C:\somedir\>ren -hélice hélice

我知道如果我把这行放在一个 .bat 文件中,我会得到以下结果:

C:\somedir\>ren -hÚlice hÚlice

看到了吗? é 已被 Ú 取代。

命令输出也是如此。如果我dir shell 中的某个目录,则输出很好。如果我将此输出重定向到文件,则会转换一些字符。

那么我如何告诉 cmd.exe 如何解释在我的批处理文件中显示为 é 的内容,实际上是 é 而不是 Ú 或逗号?

所以在执行 .bat 文件时没有办法给出关于它写入的代码页的提示?

【问题讨论】:

    标签: windows encoding batch-file cmd


    【解决方案1】:

    您必须使用 OEM 编码保存批处理文件。如何执行此操作取决于您的文本编辑器。在这种情况下使用的编码也会有所不同。对于西方文化,它通常是 CP850。

    批处理文件和编码实际上是两个彼此并不特别喜欢的东西。不幸的是,您会注意到 Unicode 也无法在那里使用(即使环境变量处理得很好)。

    或者,您可以将控制台设置为使用另一个代码页:

    chcp 1252
    

    应该可以解决问题。至少在这里对我有用。

    当您进行输出重定向时,例如使用dir,同样的规则适用。使用控制台窗口的代码页。您可以使用/u 切换到cmd.exe 来强制Unicode 输出重定向,这会导致生成的文件为UTF-16。

    至于一般cmd.exe中的编码和代码页,也请看这个问题:

    编辑: 至于您的编辑:不,cmd 始终假定批处理文件要写入控制台默认代码页。但是,您可以轻松地在批处理开头包含 chcp

    chcp 1252>NUL
    ren -hélice hélice
    

    为了使直接从命令行使用时更加健壮,您可能需要记住旧代码页并在之后恢复它:

    @echo off
    for /f "tokens=2 delims=:." %%x in ('chcp') do set cp=%%x
    chcp 1252>nul
    ren -hélice hélice
    chcp %cp%>nul
    

    【讨论】:

    • chcp 在 .bat 中有效,即使回显是错误的。但是,如果我在控制台做chcp 1252,然后输入test.bat,还是错了……
    • 当然是错的。 type 对代码页一无所知,因此它假定您当前设置的代码页。批处理中的chcp 所做的是更改 该代码页,因此结果不同。无论如何,我将此更多地作为一种解决方法。正确的解决方法是将批处理文件保存为正确的编码。
    • 其实字符“输入”和字符“输出”到屏幕是两个不同的东西。如果我更改控制台的警察:chcp 850 后跟 type 给我 hÛlice chcp 1252 后跟 type 给我 hélice 似乎默认的光栅警察代码页没有被 chcp 更改
    • 这对我来说几乎没有意义。但是,是的,基本上使用chcp 设置的代码页决定了(a)内置命令如何处理编码以及(b)可以显示哪些字符。
    • 要制作支持更多通用字符集的 bat 脚本,您可能希望在批处理脚本中使用 chcp 65001 (UTF-8) 而不是 chcp 1252。但是,我觉得很讽刺,如果您将该 bat 文件保存为带有 BOM 的 UTF-8,并且您的控制台是 850,那么由于第一行开头的奇怪字符(即物料清单)。但是通过将文件保存为没有 BOM 的 UTF-8,它工作得很好!
    【解决方案2】:

    我遇到了这个问题,这是我找到的解决方案。在当前代码页中找到您要查找的字符的十进制数。

    例如,我在代码页 437 中(chcp 告诉你),我想要一个度数符号,. http://en.wikipedia.org/wiki/Code_page_437 告诉我度数符号是 248 号。

    然后你会找到具有相同数字的 Unicode 字符。

    248 (U+00F8) 处的 Unicode 字符是 .

    如果您在批处理脚本中插入 Unicode 字符,它将在控制台中显示为您想要的字符。

    所以我的批处理文件

    echo
    

    打印

    °
    

    【讨论】:

      【解决方案3】:

      我创建了以下块,将其放在批处理文件的开头:

      set Filename=%0
      IF "%Filename:~-8%" == "-850.bat" GOTO CONVERT_CODEPAGE_END
          rem Converting code page from 1252 to 850.
          rem My editors use 1252, my batch uses 850.
          rem We create a converted -850.bat file, and then launch it.
          set File850=%~n0-850.bat
          PowerShell.exe -Command "get-content %0 | out-file -encoding oem -filepath %File850%"
          call %File850%
          del %File850%
          EXIT /b 0
      :CONVERT_CODEPAGE_END
      

      【讨论】:

        【解决方案4】:

        我关心三个概念:

        1. 输出控制台编码

        2. 命令行内部编码(使用 chcp 更改)

        3. .bat 文本编码

        对我来说最简单的方案:我将在相同的编码中提到前两个,比如 CP850,我将以相同的编码存储我的 .bat(在 Notepad++ 中,菜单 编码 → 字符集 → 西欧OEM 850)。

        但是假设有人递给我一个 .bat 的另一种编码,比如 CP1252(在 Notepad++ 中,菜单编码* → 字符集西欧Windows-第1252章

        然后我会更改命令行内部编码,使用 chcp 1252。

        这会更改它用于与其他进程(无论是输入设备还是输出控制台)通信的编码。

        所以我的命令行实例将通过其 STDOUT 文件描述符有效地发送 1252 中的字符,但是当控制台将它们解码为 850(é 是 Ú)时会出现乱码。

        然后我修改文件如下:

        @echo off
        
        perl -e "use Encode qw/encode decode/;" -e "print encode('cp850', decode('cp1252', \"ren -hlice hlice\n\"));"
        ren -hlice hlice
        

        首先我关闭回显,因此命令不会输出,除非明确执行回显...或 perl -e "print..."

        然后我每次需要输出一些东西的时候都会放这个样板

        perl -e "使用Encode qw/encode decode/;" -e "打印编码('cp850', decode('cp1252', \"ren -hélice hélice\n\"));"

        我用我要显示的实际文本代替:ren -hélice hélice。

        而且我可能需要将控制台编码替换为 cp850,并将其他端编码替换为 cp1252。

        在下面我放了所需的命令。

        我确实将有问题的行分成了输出部分和真正的命令部分。

        • 我首先确定的是:“é”通过转码被解释为“é”。由于控制台和文件的编码不同,因此所有输出语句都是必需的。

        • 第二个,真正的命令(在 @echo 关闭的情况下喃喃自语),知道我们在 chcp 和 .bat 文本中具有相同的编码,足以确保正确的字符解释。

        【讨论】:

          【解决方案5】:

          我在 R 中的代码中有抛光符号(例如 ą、ę、ź、ż 等),并且在使用 .bat 文件运行此 R 脚本时遇到问题(在输出文件中.Rout 而不是那些符号,而是像 %、&、# 等符号,并且代码没有运行到最后)。

          我的解决方案:

          1. 使用编码保存 R 脚本:文件 > 使用编码保存 > CP1250
          2. 运行 .bat 文件

          它对我有用,但如果仍然存在问题,请尝试使用其他编码。

          【讨论】:

            【解决方案6】:

            在 Visual Studio Code 中,点击底部的编码,选择Save with encoding,然后选择DOS(CP437)

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多