使用 Win10 命令提示符自带命令实现彩色输出

前言

原理是使用 ANSI 转义序列(ANSI escape code) 来控制文本的颜色,在 Win10 系统的 命令提示符 / 命令行 / 控制台 / cmd 的窗口中仅使用 cmd.exe 内置的命令来实现彩色输出,无论是在 Command Prompt(命令提示符) 中还是 .bat / .cmd 批处理脚本中。

ANSI 转义序列 支持的颜色: 3/4 bit(8/16色)8 bit(256色)24 bit(RGB真彩色)

限制:Win10 较旧的版本可能不支持。

本文仅作分享,不保证准确性。

目录

  • 前言
  • 目录
  • 简介
    • FAQ
    • 原理与方法
  • 3/4 bit(8/16色)
  • 8 bit(256色)
  • 24 bit(RGB真彩色)
  • 参考

简介

FAQ

  • Q:Windows 从什么版本开始支持使用彩色化输出?
    A:不知道。
  • Q:命令提示符还支持其他 ANSI 转义序列 吗?
    A:支持不少,但不清楚支持多少。
  • Q:内置命令是 cmd.exe 提供的?
    A:不清楚……
  • Q:这有什么用吗?
    A:鉴于 cmd / bat 脚本过于过时,以及不同版本的系统中兼容性的问题,大概没什么用。

原理与方法

通过 prompt 命令获得 ^[ / ESC ( 27 / 0x1b / 033 ) 字符后,直接用 echo 命令配合 ANSI 转义序列 来输出指定颜色的文本。

echo ^[[36mCyan^[[m

  • ^[ESC 字符,而不是 ^ [ 两个字符的组合,输入方法见下方。
  • ^[[36m:青色前景
  • ^[[m:默认颜色

ANSI 转义序列 的格式与详细可以搜索或者阅读底部的参考链接,在此不再赘述。

ESC 字符的获取/输入方法

命令提示符中

  • Ctrl+[

    • 同时按下 Ctrl 和 [ 键。
  • Alt+2(小键盘)+7(小键盘)

    • 按住 Alt 键,依次输入小键盘的 2、7,松开 Alt 键。
  • 输入命令:

    1
    @for /f "delims=#" %i in ('prompt #$E#^&echo on^&for %a in ^(1^) do rem') do set "ESC_CHAR=%%i"
  • 或者直接输出 ANSI 转义序列:

    1
    @for /f "delims=#" %i in ('prompt #$E#^&echo on^&for %a in ^(1^) do rem') do @echo;%i[36mCyan%i[m

脚本中

  • 命令:

    1
    for /f "delims=#" %%i in ('prompt #$E#^&echo on^&for %%a in ^(1^) do rem') do set "ESC_CHAR=%%i"
  • 编辑器中输入 Alt+2(小键盘)+7(小键盘)(如支持)。

  • 使用编辑器提供的功能(如有)来输入特殊字符 ESC


3/4 bit(8/16色)

  • ^[[m / ^[[0m:默认颜色(重置)
  • ^[[<n>m:指定前景色/背景色
    • <n>:颜色代码,
      30-37:指定前景色;
      40-47:指定背景色。
  • ^[[36m:青色前景
  • ^[[41m:红色背景
    • ^[[36;41m:青色前景+红色背景
  • ^[[1m:开启高亮前景
  • ^[[22m:关闭高亮前景
    • ^[[1;36;41m高亮青色前景+红色背景
    • ^[[22;36;41m:正常青色前景+红色背景
  • ^[[7m:开启反显(交换前景和背景颜色)
  • ^[[27m:关闭反显
    • ^[[7;36;41m:红色前景+青色背景

8色

颜色 前景色代码 背景色代码 R G B
黑(K) 30 40 0 0 0
红(R) 31 41 128 0 0
绿(G) 32 42 0 128 0
黄(Y) 33 43 128 128 0
蓝(B) 34 44 0 0 128
品红(M) 35 45 128 0 128
青(C) 36 46 0 128 128
37 47 128 128 128

来源:https://zh.wikipedia.org/zh-cn/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#3/4%E4%BD%8D

RGB + CMYK

注:16色就是加上高亮的颜色。


8 bit(256色)

  • ^[[38;5;<n>m:指定前景色为代码 n 的颜色
  • ^[[48;5;<n>m:指定背景色为代码 n 的颜色
    • <n>:颜色的代码,范围 0-255。颜色代码的详情和换算不在此赘述。
  • ^[[38;5;39m:指定前景色为代码 39 的“浅蓝”
  • ^[[48;5;219m:指定背景色为代码 219 的“浅粉”
  • ^[[38;5;39;48;5;219m:指定前景色为“浅蓝”,背景色为“浅粉”

bat 脚本列出 256 色:

输出 6 列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@echo off
::src: https://stackoverflow.com/a/5344911
set ESC_CHAR=
@for /f "delims=#" %%i in ('prompt #$E#^&echo on^&for %%a in ^(1^) do rem') do set ESC_CHAR=%%i

setlocal enabledelayedexpansion
set newline=
set /a nlcnt=8
for /l %%i in (0,1,15) do (
set /a clrstr=1000+%%i
set /p "str=%ESC_CHAR%[7;40;38;5;%%im !clrstr:~-3! %ESC_CHAR%[m"<nul
set /a "newline=(%%i+1)%%nlcnt"
if "!newline!" equ "0" echo.
)
set newline=
set /a nlcnt=6
for /l %%r in (0,1,5) do (
for /l %%i in (0,1,35) do (
set /a "clrnum=(36*%%r)+%%i+16"
set /a clrstr=1000+clrnum
set /p "str=%ESC_CHAR%[7;40;38;5;!clrnum!m !clrstr:~-3! %ESC_CHAR%[m"<nul
set /a "newline=(clrnum-15)%%nlcnt"
if "!newline!" equ "0" echo.
)
)
set newline=
set /a nlcnt=8
for /l %%i in (232,1,255) do (
set /a clrstr=1000+%%i
set /p "str=%ESC_CHAR%[7;40;38;5;%%im !clrstr:~-3! %ESC_CHAR%[m"<nul
set /a "newline=(%%i-231)%%nlcnt"
if "!newline!" equ "0" echo.
)
endlocal
pause>nul

输出 36 列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@echo off
::src: https://stackoverflow.com/a/5344911
set ESC_CHAR=
@for /f "delims=#" %%i in ('prompt #$E#^&echo on^&for %%a in ^(1^) do rem') do set ESC_CHAR=%%i

setlocal enabledelayedexpansion
set newline=
set /a nlcnt=36
for /l %%i in (0,1,255) do (
set /a clrstr=1000+%%i
set /p "str=%ESC_CHAR%[7;48;5;0;38;5;%%im !clrstr:~-3! %ESC_CHAR%[m"<nul
set /a "newline=(%%i+1)%%(16)"
if %%i geq 16 set /a "newline=(%%i-15)%%(%nlcnt%)"
if "!newline!" equ "0" echo.
)
endlocal
pause>nul

输出 18 列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@echo off
::src: https://stackoverflow.com/a/5344911
set ESC_CHAR=
@for /f "delims=#" %%i in ('prompt #$E#^&echo on^&for %%a in ^(1^) do rem') do set ESC_CHAR=%%i

setlocal enabledelayedexpansion
for /l %%i in (0,1,15) do (
set /a clrstr=1000+%%i
set /p "str=%ESC_CHAR%[7;40;38;5;%%im !clrstr:~-3! %ESC_CHAR%[m"<nul
)
echo.
for /l %%r in (0,1,5) do (
for /l %%i in (0,1,17) do (
set /a "clrnum=(36*%%r)+%%i+16"
set /a clrstr=1000+clrnum
set /p "str=%ESC_CHAR%[7;40;38;5;!clrnum!m !clrstr:~-3! %ESC_CHAR%[m"<nul
)
echo.
)
for /l %%r in (0,1,5) do (
for /l %%i in (18,1,35) do (
set /a "clrnum=(36*%%r)+%%i+16"
set /a clrstr=1000+clrnum
set /p "str=%ESC_CHAR%[7;40;38;5;!clrnum!m !clrstr:~-3! %ESC_CHAR%[m"<nul
)
echo.
)
for /l %%i in (232,1,255) do (
set /a clrstr=1000+%%i
set /p "str=%ESC_CHAR%[7;40;38;5;%%im !clrstr:~-3! %ESC_CHAR%[m"<nul
)
endlocal
pause>nul

24 bit(RGB真彩色)

  • ^[[38;2;<r>;<g>;<b>m:指定前景色的 RGB
  • ^[[48;2;<r>;<g>;<b>m:指定背景色的 RGB
    • <r> / <g> / <b>
      0 <= r, g, b <=255

bat 脚本简略显示 24 bit 颜色:

输出 108 列 18 行 1944(6*18*18) 色(可自定义)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@echo off
::src: https://stackoverflow.com/a/5344911
set ESC_CHAR=
@for /f "delims=#" %%i in ('prompt #$E#^&echo on^&for %%a in ^(1^) do rem') do set ESC_CHAR=%%i

setlocal enabledelayedexpansion
REM 建议参数:2, 4, 6, 16, 18, 52, 86, 256
set /a rmax=6-1 &rem 组数-1
set /a gmax=18-1 &rem 行数-1
set /a bmax=18-1 &rem 每组的列数-1
for /l %%g in (0,1,%gmax%) do (
for /l %%r in (0,1,%rmax%) do (
for /l %%b in (0,1,%bmax%) do (
set /a "r=%%r*(255/rmax)"
set /a "g=%%g*(255/gmax)"
set /a "b=%%b*(255/bmax)"
set /p "str=%ESC_CHAR%[7;40;38;2;!r!;!g!;!b!m %ESC_CHAR%[m"<nul
)
)
echo.
)
endlocal
pause>nul

输出 16 列 256 行 4096(16*16*16) 色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@echo off
::src: https://stackoverflow.com/a/5344911
set ESC_CHAR=
@for /f "delims=#" %%i in ('prompt #$E#^&echo on^&for %%a in ^(1^) do rem') do set ESC_CHAR=%%i

setlocal enabledelayedexpansion
for /l %%r in (0,1,15) do (
for /l %%g in (0,1,15) do (
for /l %%b in (0,1,15) do (
set /a "r=%%r*17"
set /a "g=%%g*17"
set /a "b=%%b*17"
set /p "str=%ESC_CHAR%[7;40;38;2;!r!;!g!;!b!m %ESC_CHAR%[m"<nul
)
echo.
)
)
endlocal
pause>nul

参考

0%