如何在 Windows 批处理文件中使用多种颜色?

我想知道是否有可能在一个 Windows 批处理文件的同一行上有不同颜色的文本,例如,如果它说

echo hi world

我希望“嗨”是一种颜色,“世界”是另一种颜色。也许我可以将 COLOR 命令设置为一个变量:

set color1= color 2
set color9= color A

然后将它们部署在同一行上

echo hi world

但我不知道该怎么做。

134849 次浏览

您应该从 Http://www.mailsend-online.com/blog/setting-text-color-in-a-batch-file.html 也可以从 Www.mailsend-online.com/blog/?p=41 它们都在这一页的底部。 Extract both folders to the desktop 并复制可执行文件(。Exe 文件)从提取的文件夹中转移到 C: Windows 目录。这将允许从命令行执行它们。 Open up notepad and copy the following into it:

@echo off

Chgcolor 03

你好

彩色的

echoj "world"

Chgcolor 07

Echoj $0a

将文件保存到桌面为 hi.bat。现在打开命令提示符并导航到 Desktop 文件夹,键入“ hi.bat”而不带引号。这应该让你开始确保阅读这两个网页,以获得一个完整的教程。

您可以在没有任何外部程序的情况下进行多色输出。

@echo off
SETLOCAL EnableDelayedExpansion
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
set "DEL=%%a"
)
echo say the name of the colors, don't read


call :ColorText 0a "blue"
call :ColorText 0C "green"
call :ColorText 0b "red"
echo(
call :ColorText 19 "yellow"
call :ColorText 2F "black"
call :ColorText 4e "white"


goto :eof


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

It uses the color feature of the findstr command.

可以将 Findstr 配置为以定义的颜色输出行号或文件名。
因此,我首先创建一个文本为文件名的文件,其内容是一个单一的 <backspace>字符(ASCII 8)。
然后搜索文件中的所有非空行并使用 null,这样文件名将以正确的颜色输出,并附加一个冒号,但是该冒号将立即被 <backspace>删除。

编辑: 一年后... ... 所有字符都有效

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


rem Prepare a file "X" with only one dot
<nul > X set /p ".=."


call :color 1a "a"
call :color 1b "b"
call :color 1c "^!<>&| %%%%"*?"
exit /b


:color
set "param=^%~2" !
set "param=!param:"=\"!"
findstr /p /A:%1 "." "!param!\..\X" nul
<nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
exit /b

这对有效的路径/文件名使用规则。
如果 \..\在路径中,前缀元素将被完全删除,并且不需要这个元素只包含有效的文件名字符。

Jeb 经过编辑的回答几乎解决了所有问题,但在以下几个方面存在问题:

"a\b\"
"a/b/"
"\"
"/"
"."
".."
"c:"

我修改了他的技术,我认为它可以真正处理任何可打印字符串,除了长度限制。

其他改进:

  • 将%TEMP%位置用于临时文件,因此不再需要对当前目录的写访问权限。

  • 创建了2个变量,一个使用字符串文字,另一个使用包含字符串的变量的名称。变量版本通常不太方便,但它消除了一些特殊的字符转义问题。

  • 添加了/n 选项作为可选的第3个参数,以便在输出的末尾附加一个换行符。

退格不能跨越换行符,因此如果换行符,该技术可能会出现问题。例如,如果控制台的行宽为80,则打印长度在74-79之间的字符串将无法正常工作。

@echo off
setlocal


call :initColorPrint


call :colorPrint 0a "a"
call :colorPrint 0b "b"
set "txt=^" & call :colorPrintVar 0c txt
call :colorPrint 0d "<"
call :colorPrint 0e ">"
call :colorPrint 0f "&"
call :colorPrint 1a "|"
call :colorPrint 1b " "
call :colorPrint 1c "%%%%"
call :colorPrint 1d ^"""
call :colorPrint 1e "*"
call :colorPrint 1f "?"
call :colorPrint 2a "!"
call :colorPrint 2b "."
call :colorPrint 2c ".."
call :colorPrint 2d "/"
call :colorPrint 2e "\"
call :colorPrint 2f "q:" /n
echo(
set complex="c:\hello world!/.\..\\a//^<%%>&|!" /^^^<%%^>^&^|!\
call :colorPrintVar 74 complex /n


call :cleanupColorPrint


exit /b


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


:colorPrint Color  Str  [/n]
setlocal
set "str=%~2"
call :colorPrintVar %1 str %3
exit /b


:colorPrintVar  Color  StrVar  [/n]
if not defined %~2 exit /b
setlocal enableDelayedExpansion
set "str=a%DEL%!%~2:\=a%DEL%\..\%DEL%%DEL%%DEL%!"
set "str=!str:/=a%DEL%/..\%DEL%%DEL%%DEL%!"
set "str=!str:"=\"!"
pushd "%temp%"
findstr /p /A:%1 "." "!str!\..\x" nul
if /i "%~3"=="/n" echo(
exit /b


:initColorPrint
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do set "DEL=%%a"
<nul >"%temp%\x" set /p "=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%.%DEL%"
exit /b


:cleanupColorPrint
del "%temp%\x"
exit /b


更新日期2012-11-27

此方法在 XP 上失败,因为 FINDSTR 在屏幕上将后退空间显示为一个句点。Jeb 最初的答案适用于 XP,尽管已经指出了一些局限性


更新日期2012-12-14

服务提示SS64有许多开发活动。事实证明,如果在命令行中提供,FINDSTR 还会损坏包含扩展 ASCII 的文件名。我更新了我的 问与答

下面是一个可以在 XP 上运行的版本,它支持除0x00(null)、0x0A (linefeed)和0x0D (回车)之外的所有单字节字符。但是,当在 XP 上运行时,大多数控制字符将显示为点。这是 XP 上 FINDSTR 的一个不可避免的固有特性。

不幸的是,添加对 XP 和扩展 ASCII 字符的支持会降低例程的速度:-(

只是为了好玩,我从 Joan Stark 的 ASCII 艺术画廊中抓取了一些彩色 ASCII 艺术品,并将其与 ColorPrint 一起使用。我添加了一个: c 入口点只是为了速记,并处理引号文字的问题。

@echo off
setlocal disableDelayedExpansion
set q=^"
echo(
echo(
call :c 0E "                ,      .-;" /n
call :c 0E "             ,  |\    / /  __," /n
call :c 0E "             |\ '.`-.|  |.'.-'" /n
call :c 0E "              \`'-:  `; : /" /n
call :c 0E "               `-._'.  \'|" /n
call :c 0E "              ,_.-=` ` `  ~,_" /n
call :c 0E "               '--,.    "&call :c 0c ".-. "&call :c 0E ",=!q!." /n
call :c 0E "                 /     "&call :c 0c "{ "&call :c 0A "* "&call :c 0c ")"&call :c 0E "`"&call :c 06 ";-."&call :c 0E "}" /n
call :c 0E "                 |      "&call :c 0c "'-' "&call :c 06 "/__ |" /n
call :c 0E "                 /          "&call :c 06 "\_,\|" /n
call :c 0E "                 |          (" /n
call :c 0E "             "&call :c 0c "__ "&call :c 0E "/ '          \" /n
call :c 02 "     /\_    "&call :c 0c "/,'`"&call :c 0E "|     '   "&call :c 0c ".-~!q!~~-." /n
call :c 02 "     |`.\_ "&call :c 0c "|   "&call :c 0E "/  ' ,    "&call :c 0c "/        \" /n
call :c 02 "   _/  `, \"&call :c 0c "|  "&call :c 0E "; ,     . "&call :c 0c "|  ,  '  . |" /n
call :c 02 "   \   `,  "&call :c 0c "|  "&call :c 0E "|  ,  ,   "&call :c 0c "|  :  ;  : |" /n
call :c 02 "   _\  `,  "&call :c 0c "\  "&call :c 0E "|.     ,  "&call :c 0c "|  |  |  | |" /n
call :c 02 "   \`  `.   "&call :c 0c "\ "&call :c 0E "|   '     "&call :c 0A "|"&call :c 0c "\_|-'|_,'\|" /n
call :c 02 "   _\   `,   "&call :c 0A "`"&call :c 0E "\  '  . ' "&call :c 0A "| |  | |  |           "&call :c 02 "__" /n
call :c 02 "   \     `,   "&call :c 0E "| ,  '    "&call :c 0A "|_/'-|_\_/     "&call :c 02 "__ ,-;` /" /n
call :c 02 "    \    `,    "&call :c 0E "\ .  , ' .| | | | |   "&call :c 02 "_/' ` _=`|" /n
call :c 02 "     `\    `,   "&call :c 0E "\     ,  | | | | |"&call :c 02 "_/'   .=!q!  /" /n
call :c 02 "     \`     `,   "&call :c 0E "`\      \/|,| ;"&call :c 02 "/'   .=!q!    |" /n
call :c 02 "      \      `,    "&call :c 0E "`\' ,  | ; "&call :c 02 "/'    =!q!    _/" /n
call :c 02 "       `\     `,  "&call :c 05 ".-!q!!q!-. "&call :c 0E "': "&call :c 02 "/'    =!q!     /" /n
call :c 02 "    jgs _`\    ;"&call :c 05 "_{  '   ; "&call :c 02 "/'    =!q!      /" /n
call :c 02 "       _\`-/__"&call :c 05 ".~  `."&call :c 07 "8"&call :c 05 ".'.!q!`~-. "&call :c 02 "=!q!     _,/" /n
call :c 02 "    __\      "&call :c 05 "{   '-."&call :c 07 "|"&call :c 05 ".'.--~'`}"&call :c 02 "    _/" /n
call :c 02 "    \    .=!q!` "&call :c 05 "}.-~!q!'"&call :c 0D "u"&call :c 05 "'-. '-..'  "&call :c 02 "__/" /n
call :c 02 "   _/  .!q!    "&call :c 05 "{  -'.~('-._,.'"&call :c 02 "\_,/" /n
call :c 02 "  /  .!q!    _/'"&call :c 05 "`--; ;  `.  ;" /n
call :c 02 "   .=!q!  _/'      "&call :c 05 "`-..__,-'" /n
call :c 02 "    __/'" /n
echo(


exit /b


:c
setlocal enableDelayedExpansion
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


:colorPrint Color  Str  [/n]
setlocal
set "s=%~2"
call :colorPrintVar %1 s %3
exit /b


:colorPrintVar  Color  StrVar  [/n]
if not defined DEL call :initColorPrint
setlocal enableDelayedExpansion
pushd .
':
cd \
set "s=!%~2!"
:: The single blank line within the following IN() clause is critical - DO NOT REMOVE
for %%n in (^"^


^") do (
set "s=!s:\=%%~n\%%~n!"
set "s=!s:/=%%~n/%%~n!"
set "s=!s::=%%~n:%%~n!"
)
for /f delims^=^ eol^= %%s in ("!s!") do (
if "!" equ "" setlocal disableDelayedExpansion
if %%s==\ (
findstr /a:%~1 "." "\'" nul
<nul set /p "=%DEL%%DEL%%DEL%"
) else if %%s==/ (
findstr /a:%~1 "." "/.\'" nul
<nul set /p "=%DEL%%DEL%%DEL%%DEL%%DEL%"
) else (
>colorPrint.txt (echo %%s\..\')
findstr /a:%~1 /f:colorPrint.txt "."
<nul set /p "=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
)
)
if /i "%~3"=="/n" echo(
popd
exit /b




:initColorPrint
for /f %%A in ('"prompt $H&for %%B in (1) do rem"') do set "DEL=%%A %%A"
<nul >"%temp%\'" set /p "=."
subst ': "%temp%" >nul
exit /b




:cleanupColorPrint
2>nul del "%temp%\'"
2>nul del "%temp%\colorPrint.txt"
>nul subst ': /d
exit /b

中介绍了几种方法
如何在 NT 脚本中使用不同颜色的回声线
Http://www.netikka.net/tsneti/info/tscmd051.htm

其中一个选择: 如果你能掌握 QBASIC,使用颜色是相对容易的:

  @echo off & setlocal enableextensions
for /f "tokens=*" %%f in ("%temp%") do set temp_=%%~sf
set skip=
findstr "'%skip%QB" "%~f0" > %temp_%\tmp$$$.bas
qbasic /run %temp_%\tmp$$$.bas
for %%f in (%temp_%\tmp$$$.bas) do if exist %%f del %%f
endlocal & goto :EOF
::
CLS 'QB
COLOR 14,0 'QB
PRINT "A simple "; 'QB
COLOR 13,0 'QB
PRINT "color "; 'QB
COLOR 14,0 'QB
PRINT "demonstration" 'QB
PRINT "By Prof. (emer.) Timo Salmi" 'QB
PRINT 'QB
FOR j = 0 TO 7 'QB
FOR i = 0 TO 15 'QB
COLOR i, j 'QB
PRINT LTRIM$(STR$(i)); " "; LTRIM$(STR$(j)); 'QB
COLOR 1, 0 'QB
PRINT " "; 'QB
NEXT i 'QB
PRINT 'QB
NEXT j 'QB
SYSTEM 'QB

实际上,这可以在不创建临时文件的情况下完成。 Jeb 和 dbenham 描述的方法甚至可以在不包含回程空间的目标文件中工作。关键点是 findstr.exe 识别的行不能以 CRLF 结束。 So the obvious text file to scan with a line not ending with a CRLF is the invoking batch itself, provided that we end it with such a line! 这里是一个更新的示例脚本,以这种方式工作..。

与前一个例子相比的变化:

  • 在最后一行使用一个破折号作为可搜索字符串。(必须是短的,并且在批处理中不能出现在其他任何地方。)
  • 重命名的例程和变量更加面向对象: -)
  • 删除了一个调用级别,以略微提高性能。
  • 添加注释(从: # 开始,使其看起来更像大多数其他脚本语言。)

@echo off
setlocal


call :Echo.Color.Init


goto main


:Echo.Color %1=Color %2=Str [%3=/n]
setlocal enableDelayedExpansion
set "str=%~2"
:Echo.Color.2
:# Replace path separators in the string, so that the final path still refers to the current path.
set "str=a%ECHO.DEL%!str:\=a%ECHO.DEL%\..\%ECHO.DEL%%ECHO.DEL%%ECHO.DEL%!"
set "str=!str:/=a%ECHO.DEL%/..\%ECHO.DEL%%ECHO.DEL%%ECHO.DEL%!"
set "str=!str:"=\"!"
:# Go to the script directory and search for the trailing -
pushd "%ECHO.DIR%"
findstr /p /r /a:%~1 "^^-" "!str!\..\!ECHO.FILE!" nul
popd
:# Remove the name of this script from the output. (Dependant on its length.)
for /l %%n in (1,1,12) do if not "!ECHO.FILE:~%%n!"=="" <nul set /p "=%ECHO.DEL%"
:# Remove the other unwanted characters "\..\: -"
<nul set /p "=%ECHO.DEL%%ECHO.DEL%%ECHO.DEL%%ECHO.DEL%%ECHO.DEL%%ECHO.DEL%%ECHO.DEL%"
:# Append the optional CRLF
if not "%~3"=="" echo.
endlocal & goto :eof


:Echo.Color.Var %1=Color %2=StrVar [%3=/n]
if not defined %~2 goto :eof
setlocal enableDelayedExpansion
set "str=!%~2!"
goto :Echo.Color.2


:Echo.Color.Init
set "ECHO.COLOR=call :Echo.Color"
set "ECHO.DIR=%~dp0"
set "ECHO.FILE=%~nx0"
set "ECHO.FULL=%ECHO.DIR%%ECHO.FILE%"
:# Use prompt to store a backspace into a variable. (Actually backspace+space+backspace)
for /F "tokens=1 delims=#" %%a in ('"prompt #$H# & echo on & for %%b in (1) do rem"') do set "ECHO.DEL=%%a"
goto :eof


:main
call :Echo.Color 0a "a"
call :Echo.Color 0b "b"
set "txt=^" & call :Echo.Color.Var 0c txt
call :Echo.Color 0d "<"
call :Echo.Color 0e ">"
call :Echo.Color 0f "&"
call :Echo.Color 1a "|"
call :Echo.Color 1b " "
call :Echo.Color 1c "%%%%"
call :Echo.Color 1d ^"""
call :Echo.Color 1e "*"
call :Echo.Color 1f "?"
:# call :Echo.Color 2a "!"
call :Echo.Color 2b "."
call :Echo.Color 2c ".."
call :Echo.Color 2d "/"
call :Echo.Color 2e "\"
call :Echo.Color 2f "q:" /n
echo(
set complex="c:\hello world!/.\..\\a//^<%%>&|!" /^^^<%%^>^&^|!\
call :Echo.Color.Var 74 complex /n


exit /b


:# The following line must be last and not end by a CRLF.
-

附言。我有一个问题的输出!在前面的例子中没有的字符。(或者至少你没有同样的症状。)接受调查。

如果您有一个现代的 Windows (已经安装了 Powershell) ,以下操作也可以很好地工作

call :PrintBright Something Something


(do actual batch stuff here)


call :PrintBright Done!
goto :eof




:PrintBright
powershell -Command Write-Host "%*" -foreground "White"

根据您的需要调整颜色。

是的,使用 cmdcolor是可能的:

echo \033[32mhi \033[92mworld

hi为深绿色,world为浅绿色。

没有外部工具。这是一个自编译的 Bat/. net 混合动力车(应该保存为 .BAT) ,可以在任何已安装的系统上使用。Net 框架(很少看到没有。NET 框架,即使是最老的 XP/2003安装)。它使用 jscript.net 编译器创建一个 exe,该 exe 能够仅为当前行打印具有不同背景/前景颜色的字符串。

@if (@X)==(@Y) @end /* JScript comment
@echo off
setlocal


for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
set "jsc=%%v"
)


if not exist "%~n0.exe" (
"%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)


%~n0.exe %*


endlocal & exit /b %errorlevel%


*/


import System;


var arguments:String[] = Environment.GetCommandLineArgs();


var newLine = false;
var output = "";
var foregroundColor = Console.ForegroundColor;
var backgroundColor = Console.BackgroundColor;
var evaluate = false;
var currentBackground=Console.BackgroundColor;
var currentForeground=Console.ForegroundColor;




//http://stackoverflow.com/a/24294348/388389
var jsEscapes = {
'n': '\n',
'r': '\r',
't': '\t',
'f': '\f',
'v': '\v',
'b': '\b'
};


function decodeJsEscape(_, hex0, hex1, octal, other) {
var hex = hex0 || hex1;
if (hex) { return String.fromCharCode(parseInt(hex, 16)); }
if (octal) { return String.fromCharCode(parseInt(octal, 8)); }
return jsEscapes[other] || other;
}


function decodeJsString(s) {
return s.replace(
// Matches an escape sequence with UTF-16 in group 1, single byte hex in group 2,
// octal in group 3, and arbitrary other single-character escapes in group 4.
/\\(?:u([0-9A-Fa-f]{4})|x([0-9A-Fa-f]{2})|([0-3][0-7]{0,2}|[4-7][0-7]?)|(.))/g,
decodeJsEscape);
}




function printHelp( ) {
print( arguments[0] + "  -s string [-f foreground] [-b background] [-n] [-e]" );
print( " " );
print( " string          String to be printed" );
print( " foreground      Foreground color - a " );
print( "                 number between 0 and 15." );
print( " background      Background color - a " );
print( "                 number between 0 and 15." );
print( " -n              Indicates if a new line should" );
print( "                 be written at the end of the ");
print( "                 string(by default - no)." );
print( " -e              Evaluates special character " );
print( "                 sequences like \\n\\b\\r and etc ");
print( "" );
print( "Colors :" );
for ( var c = 0 ; c < 16 ; c++ ) {


Console.BackgroundColor = c;
Console.Write( " " );
Console.BackgroundColor=currentBackground;
Console.Write( "-"+c );
Console.WriteLine( "" );
}
Console.BackgroundColor=currentBackground;






}


function errorChecker( e:Error ) {
if ( e.message == "Input string was not in a correct format." ) {
print( "the color parameters should be numbers between 0 and 15" );
Environment.Exit( 1 );
} else if (e.message == "Index was outside the bounds of the array.") {
print( "invalid arguments" );
Environment.Exit( 2 );
} else {
print ( "Error Message: " + e.message );
print ( "Error Code: " + ( e.number & 0xFFFF ) );
print ( "Error Name: " + e.name );
Environment.Exit( 666 );
}
}


function numberChecker( i:Int32 ){
if( i > 15 || i < 0 ) {
print("the color parameters should be numbers between 0 and 15");
Environment.Exit(1);
}
}




if ( arguments.length == 1 || arguments[1].toLowerCase() == "-help" || arguments[1].toLowerCase() == "-help"   ) {
printHelp();
Environment.Exit(0);
}


for (var arg = 1; arg <= arguments.length-1; arg++ ) {
if ( arguments[arg].toLowerCase() == "-n" ) {
newLine=true;
}


if ( arguments[arg].toLowerCase() == "-e" ) {
evaluate=true;
}


if ( arguments[arg].toLowerCase() == "-s" ) {
output=arguments[arg+1];
}




if ( arguments[arg].toLowerCase() == "-b" ) {


try {
backgroundColor=Int32.Parse( arguments[arg+1] );
} catch(e) {
errorChecker(e);
}
}


if ( arguments[arg].toLowerCase() == "-f" ) {
try {
foregroundColor=Int32.Parse(arguments[arg+1]);
} catch(e) {
errorChecker(e);
}
}
}


Console.BackgroundColor = backgroundColor ;
Console.ForegroundColor = foregroundColor ;


if ( evaluate ) {
output=decodeJsString(output);
}


if ( newLine ) {
Console.WriteLine(output);
} else {
Console.Write(output);


}


Console.BackgroundColor = currentBackground;
Console.ForegroundColor = currentForeground;

例子 coloroutput.bat -s "aa\nbb\n\u0025cc" -b 10 -f 3 -n -e

你也可以检查 Carlos 的颜色函数-> http://www.dostips.com/forum/viewtopic.php?f=3&t=4453

德贝纳姆的鸟语和句法Skrebbel 的 Powershell write-host方法结合起来,似乎 Powershell 可以比 dbenham 的纯批处理方法更快地渲染复杂的艺术(好吧,至少在 Powershell 被启动一次之后)。最小的按摩弦是必要的,虽然我还没有测试这个与其他任何鸟。例如,如果你想要一个亮绿色的传输结束字符,你可能就不太走运了。:)

这个方法需要回显到一个临时文件,原因很简单,因为为每个 call :c调用 powershell 需要很长时间,而且为一个 powershell 调用排队输出要快得多。但它确实具有简单和高效的优点。

@echo off
setlocal disableDelayedExpansion
set q=^"
echo(
echo(
call :c 0E "                ,      .-;" /n
call :c 0E "             ,  |\    / /  __," /n
call :c 0E "             |\ '.`-.|  |.'.-'" /n
call :c 0E "              \`'-:  `; : /" /n
call :c 0E "               `-._'.  \'|" /n
call :c 0E "              ,_.-=` ` `  ~,_" /n
call :c 0E "               '--,.    "&call :c 0c ".-. "&call :c 0E ",=!q!." /n
call :c 0E "                 /     "&call :c 0c "{ "&call :c 0A "* "&call :c 0c ")"&call :c 0E "`"&call :c 06 ";-."&call :c 0E "}" /n
call :c 0E "                 |      "&call :c 0c "'-' "&call :c 06 "/__ |" /n
call :c 0E "                 /          "&call :c 06 "\_,\|" /n
call :c 0E "                 |          (" /n
call :c 0E "             "&call :c 0c "__ "&call :c 0E "/ '          \" /n
call :c 02 "     /\_    "&call :c 0c "/,'`"&call :c 0E "|     '   "&call :c 0c ".-~!q!~~-." /n
call :c 02 "     |`.\_ "&call :c 0c "|   "&call :c 0E "/  ' ,    "&call :c 0c "/        \" /n
call :c 02 "   _/  `, \"&call :c 0c "|  "&call :c 0E "; ,     . "&call :c 0c "|  ,  '  . |" /n
call :c 02 "   \   `,  "&call :c 0c "|  "&call :c 0E "|  ,  ,   "&call :c 0c "|  :  ;  : |" /n
call :c 02 "   _\  `,  "&call :c 0c "\  "&call :c 0E "|.     ,  "&call :c 0c "|  |  |  | |" /n
call :c 02 "   \`  `.   "&call :c 0c "\ "&call :c 0E "|   '     "&call :c 0A "|"&call :c 0c "\_|-'|_,'\|" /n
call :c 02 "   _\   `,   "&call :c 0A "`"&call :c 0E "\  '  . ' "&call :c 0A "| |  | |  |           "&call :c 02 "__" /n
call :c 02 "   \     `,   "&call :c 0E "| ,  '    "&call :c 0A "|_/'-|_\_/     "&call :c 02 "__ ,-;` /" /n
call :c 02 "    \    `,    "&call :c 0E "\ .  , ' .| | | | |   "&call :c 02 "_/' ` _=`|" /n
call :c 02 "     `\    `,   "&call :c 0E "\     ,  | | | | |"&call :c 02 "_/'   .=!q!  /" /n
call :c 02 "     \`     `,   "&call :c 0E "`\      \/|,| ;"&call :c 02 "/'   .=!q!    |" /n
call :c 02 "      \      `,    "&call :c 0E "`\' ,  | ; "&call :c 02 "/'    =!q!    _/" /n
call :c 02 "       `\     `,  "&call :c 05 ".-!q!!q!-. "&call :c 0E "': "&call :c 02 "/'    =!q!     /" /n
call :c 02 "    jgs _`\    ;"&call :c 05 "_{  '   ; "&call :c 02 "/'    =!q!      /" /n
call :c 02 "       _\`-/__"&call :c 05 ".~  `."&call :c 07 "8"&call :c 05 ".'.!q!`~-. "&call :c 02 "=!q!     _,/" /n
call :c 02 "    __\      "&call :c 05 "{   '-."&call :c 07 "|"&call :c 05 ".'.--~'`}"&call :c 02 "    _/" /n
call :c 02 "    \    .=!q!` "&call :c 05 "}.-~!q!'"&call :c 0D "u"&call :c 05 "'-. '-..'  "&call :c 02 "__/" /n
call :c 02 "   _/  .!q!    "&call :c 05 "{  -'.~('-._,.'"&call :c 02 "\_,/" /n
call :c 02 "  /  .!q!    _/'"&call :c 05 "`--; ;  `.  ;" /n
call :c 02 "   .=!q!  _/'      "&call :c 05 "`-..__,-'" /n
call :c 02 "    __/'" /n


if exist "%temp%\color.psm1" (
powershell -command "&{set-executionpolicy remotesigned; Import-Module '%temp%\color.psm1'}"
del "%temp%\color.psm1"
)


echo(


exit /b


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


:c <color pair> <string> </n>
setlocal enabledelayedexpansion
set "colors=0-black;1-darkblue;2-darkgreen;3-darkcyan;4-darkred;5-darkmagenta;6-darkyellow;7-gray;8-darkgray;9-blue;a-green;b-cyan;c-red;d-magenta;e-yellow;f-white"
set "p=%~1"
set "bg=!colors:*%p:~0,1%-=!"
set bg=%bg:;=&rem.%
set "fg=!colors:*%p:~-1%-=!"
set fg=%fg:;=&rem.%


if not "%~3"=="/n" set "br=-nonewline"
set "str=%~2" & set "str=!str:'=''!"


>>"%temp%\color.psm1" echo write-host '!str!' -foregroundcolor '%fg%' -backgroundcolor '%bg%' %br%
endlocal

结果:

enter image description here

如果您的控制台支持 ANSI 颜色代码(例如 科尼姆干杯安西康) ,您可以这样做:

SET    GRAY=%ESC%[0m
SET     RED=%ESC%[1;31m
SET   GREEN=%ESC%[1;32m
SET  ORANGE=%ESC%[0;33m
SET    BLUE=%ESC%[0;34m
SET MAGENTA=%ESC%[0;35m
SET    CYAN=%ESC%[1;36m
SET   WHITE=%ESC%[1;37m

其中 ESC 变量包含 ASCII 字符27。

我在这里找到了一种填充 ESC 变量的方法: ref = “ http://www.dostips.com/forum/viewtopic.php? p = 6827 # p6827”rel = “ nofollow”> http://www.dostips.com/forum/viewtopic.php?p=6827#p6827 使用 tasklist可以测试哪些 DLL 被加载到进程中。

下面的脚本获取运行脚本的 cmd.exe 的进程 ID。检查是否有一个 dll,将添加 ANSI 支持注入,然后设置颜色变量,以包含转义序列或为空,这取决于是否支持颜色。

@echo off


call :INIT_COLORS


echo %RED%RED %GREEN%GREEN %ORANGE%ORANGE %BLUE%BLUE %MAGENTA%MAGENTA %CYAN%CYAN %WHITE%WHITE %GRAY%GRAY


:: pause if double clicked on instead of run from command line.
SET interactive=0
ECHO %CMDCMDLINE% | FINDSTR /L %COMSPEC% >NUL 2>&1
IF %ERRORLEVEL% == 0 SET interactive=1
@rem ECHO %CMDCMDLINE% %COMSPEC% %interactive%
IF "%interactive%"=="1" PAUSE
EXIT /B 0
Goto :EOF


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
: SUBROUTINES                                                          :
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


::::::::::::::::::::::::::::::::
:INIT_COLORS
::::::::::::::::::::::::::::::::


call :supportsANSI
if ERRORLEVEL 1 (
SET GREEN=
SET RED=
SET GRAY=
SET WHITE=
SET ORANGE=
SET CYAN=
) ELSE (


:: If you can, insert ASCII CHAR 27 after equals and remove BL.String.CreateDEL_ESC routine
set "ESC="
:: use this if can't type ESC CHAR, it's more verbose, but you can copy and paste it
call :BL.String.CreateDEL_ESC


SET    GRAY=%ESC%[0m
SET     RED=%ESC%[1;31m
SET   GREEN=%ESC%[1;32m
SET  ORANGE=%ESC%[0;33m
SET    BLUE=%ESC%[0;34m
SET MAGENTA=%ESC%[0;35m
SET    CYAN=%ESC%[1;36m
SET   WHITE=%ESC%[1;37m
)


exit /b


::::::::::::::::::::::::::::::::
:BL.String.CreateDEL_ESC
::::::::::::::::::::::::::::::::
:: http://www.dostips.com/forum/viewtopic.php?t=1733
::
:: Creates two variables with one character DEL=Ascii-08 and ESC=Ascii-27
:: DEL and ESC can be used  with and without DelayedExpansion
setlocal
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
ENDLOCAL
set "DEL=%%a"
set "ESC=%%b"
goto :EOF
)


::::::::::::::::::::::::::::::::
:supportsANSI
::::::::::::::::::::::::::::::::
:: returns ERRORLEVEL 0 - YES, 1 - NO
::
:: - Tests for ConEmu, ANSICON and Clink
:: - Returns 1 - NO support, when called via "CMD /D" (i.e. no autoruns / DLL injection)
::   on a system that would otherwise support ANSI.


if "%ConEmuANSI%" == "ON" exit /b 0


call :getPID PID


setlocal


for /f usebackq^ delims^=^"^ tokens^=^* %%a in (`tasklist /fi "PID eq %PID%" /m /fo CSV`) do set "MODULES=%%a"


set MODULES=%MODULES:"=%
set NON_ANSI_MODULES=%MODULES%


:: strip out ANSI dlls from module list:
:: ANSICON adds ANSI64.dll or ANSI32.dll
set "NON_ANSI_MODULES=%NON_ANSI_MODULES:ANSI=%"
:: ConEmu attaches ConEmuHk but ConEmu also sets ConEmuANSI Environment VAR
:: so we've already checked for that above and returned early.
@rem set "NON_ANSI_MODULES=%NON_ANSI_MODULES:ConEmuHk=%"
:: Clink supports ANSI https://github.com/mridgers/clink/issues/54
set "NON_ANSI_MODULES=%NON_ANSI_MODULES:clink_dll=%"


if "%MODULES%" == "%NON_ANSI_MODULES%" endlocal & exit /b 1
endlocal


exit /b 0


::::::::::::::::::::::::::::::::
:getPID  [RtnVar]
::::::::::::::::::::::::::::::::
:: REQUIREMENTS:
::
:: Determine the Process ID of the currently executing script,
:: but in a way that is multiple execution safe especially when the script can be executing multiple times
::   - at the exact same time in the same millisecond,
::   - by multiple users,
::   - in multiple window sessions (RDP),
::   - by privileged and non-privileged (e.g. Administrator) accounts,
::   - interactively or in the background.
::   - work when the cmd.exe window cannot appear
::     e.g. running from TaskScheduler as LOCAL SERVICE or using the "Run whether user is logged on or not" setting
::
:: https://social.msdn.microsoft.com/Forums/vstudio/en-US/270f0842-963d-4ed9-b27d-27957628004c/what-is-the-pid-of-the-current-cmdexe?forum=msbuild
::
:: http://serverfault.com/a/654029/306
::
:: Store the Process ID (PID) of the currently running script in environment variable RtnVar.
:: If called without any argument, then simply write the PID to stdout.
::
::
setlocal disableDelayedExpansion
:getLock
set "lock=%temp%\%~nx0.%time::=.%.lock"
set "uid=%lock:\=:b%"
set "uid=%uid:,=:c%"
set "uid=%uid:'=:q%"
set "uid=%uid:_=:u%"
setlocal enableDelayedExpansion
set "uid=!uid:%%=:p!"
endlocal & set "uid=%uid%"
2>nul ( 9>"%lock%" (
for /f "skip=1" %%A in (
'wmic process where "name='cmd.exe' and CommandLine like '%%<%uid%>%%'" get ParentProcessID'
) do for %%B in (%%A) do set "PID=%%B"
(call )
))||goto :getLock
del "%lock%" 2>nul
endlocal & if "%~1" equ "" (echo(%PID%) else set "%~1=%PID%"
exit /b

针对 Windows10用户使用 虚拟终端虚拟终端代码的宏解决方案

对于 Windows10用户来说,它是除了直接使用 VT 序列之外最快的方法,同时也更具可读性。

::: Author T3RRY : Created 09/04/2021 : Version 1.0.7
::: Version changes:
::: - ADDED /A switch to allow absolute Y;X value to be supplied as a single switch subarg
::: - ADDED /@ switch to allow saving of cursor position. Subarg allows custom return var to store multiple positions.
::: - ADDED random subarg for /C color switch.
::: - ADDED optional companion switch to /C - '/B'
:::  - When /C random subarg is used, /B may be used with any ONE of the following: R G B C M Y
:::    to bias the output color towards Red Green Blue Cyan Magenta or Yellow
::: - ADDED support for switches with common prefix.
::: - ADDED /T timeout switch for subsecond delays
::: - CORRECTED Switch validation method to handle Switches at EOL with no subargs
::: - ADDED /E Switch to allow /C value to be preserved or Color to be changed at EOL with an integer subarg.
::: - Support REMOVED for switch usage pattern /Switch:value
:::
::: Purpose      : Color and cursor position macro for windows 10 batch files
::: - Allows rapid display of colored output at specified screen position.
:::   For more information, read the usage.
:::
::: Uses macro parameter and switch handling template.
:::  - See :  https://pastebin.com/gzL7AYpC


@Echo off


:# Windows Version control. Assigns flag true if system is windows 10.
Set "Win10="
Ver | Findstr /LIC:" 10." > nul && Set "Win10=true"


:# Test if virtual terminal codes enabled ; enable if false
:# removes win10 flag definition if version does not support Virtual Terminal sequences
If defined Win10 (
Reg Query HKCU\Console | %SystemRoot%\System32\findstr.exe /LIC:"VirtualTerminalLevel    REG_DWORD    0x1" > nul || (
Reg Add HKCU\Console /f /v VirtualTerminalLevel /t REG_DWORD /d 1
) > Nul || Set "Win10="
)
If not defined Win10 (
Echo(Virtual terminal sequences not supported on your system
Exit /B 1
)


If "%~1" == "" (
Mode 200,150
Cls
)


:# /@ Switch requires clean working driectory to execute in.
RD "%TEMP%\%~n0_Run" 2> nul && Timeout 1 > nul
MD "%TEMP%\%~n0_Run"


(Set \n=^^^


%= \n macro newline variable. Do not modify =%)


:# assign virtual terminal control character 0x27 'escape' variable \E
For /F %%a in ( 'Echo prompt $E ^| cmd' )Do Set "\E=%%a"


::# usage: %$Cout% [/?] | [/Alt | /Main] [/H [-|+]] [/T Int] [/X Int | /L Int | /R Int]
::#                [/Y Int | /U Int | /D Int] [/K |/Del Int | /I Int] [/N] [/@ {Optional:ReturnVar}]
::#                [/C Int | /C Int,Int | /C Int;Int | /C random] [/S "String"] [/E {Optional:0|Int}]
::# -----------------------------------------------------------------------------------------------------
::# Available Switches     : Description:
::# -----------------------------------------------------------------------------------------------------
::# /?                     : This help screen
::#
::# /S String              : String to be output. Tested for strings of 500 characters.
::# /S String{Substituion} : The following characters must be substituted for output:
::# /S ^!Variable:/={FS}^! : {AS}:* {DQ}:" {FS}:/ {EQ}:=
::#
::# /C Integer             : Declare output color using VT sequence
::# /C Integer,Integer     : Chain   mulitple VT color sequences
::# /C Integer;Integer     : Combine multiple VT values into the one sequence
::# /C random              : Random RGB foreground color
::# /B R|G|B|C|M|Y         : Bias /C random color toward Red Green Blue
::#                        : Cyan Magenta or Yellow. /C random must be used.
::# /E                     : Preserves /C Color value until /E 0 is used. /C must be used.
::# /E 0                   : Restores color to Black BG White FG after string output.
::# /E Integer             : Change color after string output to supplied value.
::#
::# /A Integer;Integer     : Move cursor to Line;Column    [ absolute   ]
::# /Y Integer             : Move cursor to Line Integer   [ absolute Y ]
::# /X Integer             : Move cursor to Column Integer [ absolute X ]
::# /U Integer             : Move cursor Up by Integer
::# /D Integer             : Move cursor Down by Integer
::# /R Integer             : Move cursor Right by Integer
::# /L Integer             : Move cursor Left by Integer
::#
::# /H -                   : Hide the cursor  : Note - If Cursor state is changed during a code block
::#                          redirected to a file, it cannot be changed again except within a code block.
::# /H +                   : Show the cursor
::# /Alt                   : Switch to alternate   buffer [ main buffer is preserved ]
::# /Main                  : Return to main screen buffer [ alternate buffer is cleared ]
::# /K                     : Clears text to right of current cursor position
::# /Del Integer           : Deletes Integer columns right of the cursor, shifting existing text left
::# /I Integer             : Inserts whitespace into Integer columns right of Cursor, shifting text right
::# /N                     : Output a newline after other switches are executed.
::# /T Integer             : Subsecond Delay after output. 25000 = ~1 Second [ Depending on clockspeed ]
::#
::# /@                     : Stores cursor position after execution in variables: $Cout{Y} , $Cout{X}
::#                        : and $Cout{pos} ( VT format 'IntY;IntX' )
::# /@ String-ReturnVar    : Return values to ReturnVar{pos} ReturnVar{Y} ReturnVar{X}
::#                    *!* : This switch MUST NOT be used during codeblocks that redirect output
::#                        : Slow execution time. ~ 17x slower than typical $Cout expansion
::#                        : 12/100th's vs 0.7/100th's of a second [with a clockspeed of 2904]
::#
::#                                               Notes:
::# - $Cout Macro does not support Concatenation of Expansions.
::# - No error validation is performed on switch Integer subargs. Invalid Virtual Terminal sequences
::#   will be disregarded and output as a string.
::#
::# Virtual Terminal sequence resource:
::# https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
::# -----------------------------------------------------------------------------------------------------


Set $Cout_Switches="A" "Y" "X" "U" "D" "R" "L" "H" "Alt" "Main" "K" "Del" "I" "N" "T" "B" "C" "E" "S" "@"


Set $Cout=For %%n in (1 2)Do if %%n==2 (%\n%
For %%G in ( %$Cout_Switches% )Do Set "$Cout_Switch[%%~G]="%\n%
Set "$Cout_leading.args=!$Cout_args:*/=!"%\n%
For /F "Delims=" %%G in ("!$Cout_leading.args!")Do Set "$Cout_leading.args=!$Cout_args:/%%G=!"%\n%
Set ^"$Cout_args=!$Cout_args:"=!"%\n%
Set "$Cout_i.arg=0"%\n%
For %%G in (!$Cout_leading.args!)Do (%\n%
Set /A "$Cout_i.arg+=1"%\n%
Set "$Cout_arg[!$Cout_i.arg!]=%%~G"%\n%
)%\n%
If "!$Cout_Args:~-2,1!" == "/" (%\n%
Set "$Cout_Switch[!$Cout_Args:~-1!]=true"%\n%
If not "!$Cout_Args:/?=!." == "!$Cout_Args!." Set "$Cout_Switch[help]=true"%\n%
Set "$Cout_Args=!$Cout_Args:~0,-2!"%\n%
)%\n%
For %%G in ( %$Cout_Switches% )Do If not "!$Cout_args:/%%~G =!" == "!$Cout_args!" (%\n%
Set "$Cout_Switch[%%~G]=!$Cout_Args:*/%%~G =!"%\n%
If not "!$Cout_Switch[%%~G]:*/=!" == "!$Cout_Switch[%%~G]!" (%\n%
Set "$Cout_Trail[%%~G]=!$Cout_Switch[%%~G]:*/=!"%\n%
For %%v in ("!$Cout_Trail[%%~G]!")Do (%\n%
Set "$Cout_Switch[%%~G]=!$Cout_Switch[%%~G]: /%%~v=!"%\n%
Set "$Cout_Switch[%%~G]=!$Cout_Switch[%%~G]:/%%~v=!"%\n%
)%\n%
Set "$Cout_Trail[%%~G]="%\n%
If "!$Cout_Switch[%%~G]:~-1!" == " " Set "$Cout_Switch[%%~G]=!$Cout_Switch[%%~G]:~0,-1!"%\n%
If "!$Cout_Switch[%%~G]!" == "" Set "$Cout_Switch[%%~G]=true"%\n%
)%\n%
)%\n%
If /I "!$Cout_Switch[C]!" == "random" (%\n%
If not "!$Cout_Switch[B]!" == ""   (Set "$Cout_MOD=100")Else Set "$Cout_MOD=200"%\n%
Set /A "$Cout_RR=!random! %% !$Cout_MOD! + 50,$Cout_GG=!random! %% !$Cout_MOD! + 50,$Cout_BB=!random! %% !$Cout_MOD! + 50"%\n%
If /I "!$Cout_Switch[B]!" == "R" Set "$Cout_RR=250"%\n%
If /I "!$Cout_Switch[B]!" == "G" Set "$Cout_GG=250"%\n%
If /I "!$Cout_Switch[B]!" == "B" Set "$Cout_BB=250"%\n%
If /I "!$Cout_Switch[B]!" == "M" Set /A "$Cout_RR=!Random! %% 50 + 200,Cout_GG=0,$Cout_BB=!Random! %% 50 + 200"%\n%
If /I "!$Cout_Switch[B]!" == "Y" Set /A "$Cout_RR=!Random! %% 90 + 100,Cout_GG=!Random! %% 90 + 90,$Cout_BB=0"%\n%
If /I "!$Cout_Switch[B]!" == "C" Set /A "$Cout_RR=0,Cout_GG=!Random! %% 120 + 30,$Cout_BB=175"%\n%
Set "$Cout_Switch[C]=38;2;!$Cout_RR!;!$Cout_GG!;!$Cout_BB!"%\n%
)%\n%
If "!$Cout_Switch[help]!" == "true" ((For /F "Tokens=1,2 Delims=#" %%Y in ('findstr /BLIC:"::#" "%~f0"')Do @Echo(%%Z)^| @More)%\n%
If not "!$Cout_Switch[C]!" == ""    (Set "$Cout_Color=%\E%[!$Cout_Switch[C]:,=m%\E%[!m")Else Set "$Cout_Color="%\n%
If not "!$Cout_Switch[Y]!" == ""    (Set "$Cout_Ypos=%\E%[!$Cout_Switch[Y]!d")Else Set "$Cout_Ypos="%\n%
If not "!$Cout_Switch[X]!" == ""    (Set "$Cout_Xpos=%\E%[!$Cout_Switch[X]!G")Else Set "$Cout_Xpos="%\n%
For %%d in (U D L R)Do if not "!$Cout_Switch[%%d]!" == "" (Set /A "$Cout_Switch[%%d]=!$Cout_Switch[%%d]!")%\n%
If not "!$Cout_Switch[U]!" == ""    (Set "$Cout_Yoffset=%\E%[!$Cout_Switch[U]!A")Else Set "$Cout_Yoffset="%\n%
If not "!$Cout_Switch[D]!" == ""    Set "$Cout_Yoffset=%\E%[!$Cout_Switch[D]!B"%\n%
If not "!$Cout_Switch[R]!" == ""    (Set "$Cout_Xoffset=%\E%[!$Cout_Switch[R]!C")Else Set "$Cout_Xoffset="%\n%
If not "!$Cout_Switch[L]!" == ""    Set "$Cout_Xoffset=%\E%[!$Cout_Switch[L]!D"%\n%
If "!$Cout_Switch[H]!" == "-"       Set "$Cout_Cursor=%\E%[?25l"%\n%
If "!$Cout_Switch[H]!" == "+"       Set "$Cout_Cursor=%\E%[?25h"%\n%
If "!$Cout_Switch[Main]!" == "true" (Set "$Cout_Buffer=%\E%[?1049l")Else Set "$Cout_Buffer="%\n%
If "!$Cout_Switch[Alt]!" == "true"  Set "$Cout_Buffer=%\E%[?1049h"%\n%
If not "!$Cout_Switch[A]!" == ""    (Set "$Cout_Absolutepos=%\E%[!$Cout_Switch[A]!H")Else Set "$Cout_Absolutepos="%\n%
If not "!$Cout_Switch[K]!" == ""    (Set "$Cout_LineClear=%\E%[K")Else Set "$Cout_LineClear="%\n%
If not "!$Cout_Switch[Del]!" == ""  (Set "$Cout_Delete=%\E%[!$Cout_Switch[Del]!P")Else Set "$Cout_Delete="%\n%
If not "!$Cout_Switch[I]!" == ""    (Set "$Cout_Insert=%\E%[!$Cout_Switch[I]!@")Else Set "$Cout_Insert="%\n%
If not "!$Cout_Switch[S]!" == ""    (%\n%
Set "$Cout_String=!$Cout_Switch[S]:{FS}=/!"%\n%
Set "$Cout_String=!$Cout_String:{EQ}==!"%\n%
Set "$Cout_String=!$Cout_String:{AS}=*!"%\n%
Set ^"$Cout_String=!$Cout_String:{DQ}="!"%\n%
)Else (Set "$Cout_String=")%\n%
If "!$Cout_Switch[E]!" == "true"    (Set "$Cout_EOLC=!$Cout_Color!")%\n%
If not "!$Cout_Switch[E]!" == ""    (Set "$Cout_EOLC=%\E%[!$Cout_Switch[E]!m")%\n%
If "!$Cout_EOLC!" == ""             (Set "$Cout_EOLC=%\E%[0m")%\n%
^< nul set /P "=!$Cout_Buffer!!$Cout_Cursor!!$Cout_Absolutepos!!$Cout_Ypos!!$Cout_YOffset!!$Cout_Xpos!!$Cout_XOffset!!$Cout_Delete!!$Cout_Insert!!$Cout_Color!!$Cout_LineClear!!$Cout_String!!$COUT_EOLC!"%\n%
If "!$Cout_Switch[N]!" == "true"    Echo(%\n%
If not "!$Cout_Switch[T]!" == ""    (For /L %%T in (1 1 !$Cout_Switch[T]!)Do (Call )%= Delay resetting Errorlevel to 0 =%)%\n%
If "!$Cout_Switch[help]!" == "true" Pause%\n%
If not "!$Cout_Switch[@]!" == "" (%\n%
PUSHD "%TEMP%\%~n0_Run"%\n%
Set "$Cout{pos}=" ^&Set "$Cout[Char]="%\n%
For /L %%l in (2 1 12)Do (%\n%
If not "!$Cout[Char]!" == "R" (%\n%
^<nul set /p "=%\E%[6n" %\n%
FOR /L %%z in (1 1 %%l) DO pause ^< CON ^> NUL%\n%
Set "$Cout[Char]=;"%\n%
for /F "tokens=1 skip=1 delims=*" %%C in ('"REPLACE /W ? . < con"') DO (Set "$Cout[Char]=%%C")%\n%
If "!$Cout{pos}!" == "" (Set "$Cout{pos}=!$Cout[Char]!")Else (set "$Cout{pos}=!$Cout{pos}!!$Cout[Char]:R=!")%\n%
))%\n%
For /F "tokens=1,2 Delims=;" %%X in ("!$Cout{pos}!")Do Set "$Cout{Y}=%%X" ^& Set "$Cout{X}=%%Y" %\n%
If not "!$Cout_Switch[@]!" == "true" (%\n%
Set "{Pos}!$Cout_Switch[@]!=!$Cout{pos}!"%\n%
Set /A "{Y}!$Cout_Switch[@]!=$Cout{Y},{X}!$Cout_Switch[@]!=$Cout{X}"%\n%
)%\n%
POPD "%TEMP%\%~n0_Run"%\n%
)%\n%
) Else Set $Cout_args=


:# enable macro
Setlocal EnableExtensions EnableDelayedExpansion


:# facilitate testing of the macro using parameters from the command line; or Call %~n0.bat /? to see help.


if not "%~1" == ""  (
%$Cout% %*
Exit /B !Errorlevel!
)


:# usage example Ascii art ; Bird with animation


:# ensures Y;X axis at screen home
%$Cout% /A 1;1


(
%$Cout% /H - /C 1,33 /S "                ,      .-;" /N
%$Cout% /C 1,33 /S "             ,  |\    {FS} {FS}  __," /N
%$Cout% /C 1,33 /S "             |\ '.`-.|  |.'.-'" /N
%$Cout% /C 1,33 /S "              \`'-:  `; : {FS}" /N
%$Cout% /C 1,33 /S "               `-._'.  \'|" /N
%$Cout% /C 1,33 /S "              ,_.-` ` `  ~,_" /N
%$Cout% /C 1,33 /S "               '--,.    "
%$Cout% /C 31 /S ".-. "
%$Cout% /C 1,33 /S ",{EQ}{DQ}{EQ}." /N
%$Cout% /C 1,33 /S "                 {FS}     "
%$Cout% /C 31 /S "{ "
%$Cout% /C 1,36 /S "} "
%$Cout% /C 31 /S ")"
%$Cout% /C 1,33 /S "`"
%$Cout% /C 33 /S ";-."
%$Cout% /C 1,33 /S "}" /N
%$Cout% /C 1,33 /S "                 |      "
%$Cout% /C 31 /S "'-' "
%$Cout% /C 33 /S "{FS}__ |" /N
%$Cout% /C 1,33 /S "                 {FS}          "
%$Cout% /C 33 /S "\_,\|" /N
%$Cout% /C 1,33 /S "                 |          (" /N
%$Cout% /C 1,33 /S "             "
%$Cout% /C 31 /S "__ "
%$Cout% /C 1,33 /S "{FS} '          \" /N
%$Cout% /C random /B G /S "     {FS}\_    "
%$Cout% /C 31 /S "{FS},'`"
%$Cout% /C 1,33 /S "|     '   "
%$Cout% /C 31 /S ".-~^~~-." /N
%$Cout% /C random /B G /S "     |`.\_ "
%$Cout% /C 31 /S "|   "
%$Cout% /C 1,33 /S "{FS}  ' ,    "
%$Cout% /C 31 /S "{FS}        \" /N
%$Cout% /C random /B G /S "   _{FS}  `, \"
%$Cout% /C 31 /S "|  "
%$Cout% /C 1,33 /S "; ,     . "
%$Cout% /C 31 /S "|  ,  '  . |" /N
%$Cout% /C random /B G /S "   \   `,  "
%$Cout% /C 31 /S "|  "
%$Cout% /C 1,33 /S "|  ,  ,   "
%$Cout% /C 31 /S "|  :  ;  : |" /N
%$Cout% /C random /B G /S "   _\  `,  "
%$Cout% /C 31 /S "\  "
%$Cout% /C 1,33 /S "|.     ,  "
%$Cout% /C 31 /S "|  |  |  | |" /N
%$Cout% /C random /B G /S "   \`  `.   "
%$Cout% /C 31 /S "\ "
%$Cout% /C 1,33 /S "|   '     "
%$Cout% /C 1,32 /S "|"
%$Cout% /C 31 /S "\_|-'|_,'\|" /N
%$Cout% /C random /B G /S "   _\   `,   "
%$Cout% /C 1,32 /S "`"
%$Cout% /C 1,33 /S "\  '  . ' "
%$Cout% /C 1,32 /S "| |  | |  |           "
%$Cout% /C random /B G /S "__" /N
%$Cout% /C random /B G /S "   \     `,   "
%$Cout% /C 33 /S "| ,  '    "
%$Cout% /C 1,32 /S "|_{FS}'-|_\_{FS}     "
%$Cout% /C random /B G /S "__ ,-;` {FS}" /N
%$Cout% /C random /B G /S "    \    `,    "
%$Cout% /C 33 /S "\ .  , ' .| | | | |   "
%$Cout% /C random /B G /S "_{FS}' ` _-`|" /N
%$Cout% /C random /B G /S "     `\    `,   "
%$Cout% /C 33 /S "\     ,  | | | | |"
%$Cout% /C random /B G /S "_{FS}'   .{EQ}{DQ}  {FS}" /N
%$Cout% /C random /B G /S "     \`     `,   "
%$Cout% /C 33 /S "`\      \{FS}|,| ;"
%$Cout% /C random /B G /S "{FS}'   .{EQ}{DQ}    |" /N
%$Cout% /C random /B G /S "      \      `,    "
%$Cout% /C 33 /S "`\' ,  | ; "
%$Cout% /C random /B G /S "{FS}'    {EQ}{DQ}    _{FS}" /N
%$Cout% /C random /B G /S "       `\     `,  "
%$Cout% /C random /B M /S ".{EQ}{DQ}-. "
%$Cout% /C 1,33 /S "': "
%$Cout% /C random /B G /S "{FS}'     {EQ}{DQ}    .{FS}" /N
%$Cout% /C random /B G /S "    jgs _`\    ;"
%$Cout% /C random /B M /S "_{  '   ; "
%$Cout% /C random /B G /S "{FS}'    {EQ}{DQ}      {FS}" /N
%$Cout% /C random /B G /S "       _\`-{FS}__"
%$Cout% /C random /B M /S ".~  `."
%$Cout% /C 1,35,7,48;2;130;100;0 /S "8"
%$Cout% /C random /B M /S ".'.^`~-. "
%$Cout% /C random /B G /S "{EQ}{DQ}     _,{FS}" /N
%$Cout% /C random /B G /S "    __\      "
%$Cout% /C random /B M /S "{   '-."
%$Cout% /C 1,35,7,48;2;150;130;0 /S "|"
%$Cout% /C random /B M /S ".'.--~'`}"
%$Cout% /C random /B G /S "     _{FS}" /N
%$Cout% /C random /B G /S "    \    .{EQ}{DQ}` "
%$Cout% /C random /B M /S "}.-~^'"
%$Cout% /C 1,35,7,48;2;170;150;0 /S "@"
%$Cout% /C random /B M /S "'-. '-..'  "
%$Cout% /C random /B G /S "__{FS}" /N
%$Cout% /C random /B G /S "   _{FS}  .{DQ}    "
%$Cout% /C random /B M /S "{  -'.~('-._,.'"
%$Cout% /C random /B G /S "\_,{FS}" /N
%$Cout% /C random /B G /S "  {FS}  .{DQ}    _{FS}'"
%$Cout% /C random /B M /S "`--; ;  `.  ;" /N
%$Cout% /C random /B G /S "   .{EQ}{DQ}   _{FS}'      "
%$Cout% /C random /B M /S "`-..__,-'" /N
%$Cout% /C random /B G /S "     __{FS}'" /N
) > "%~dp0parrot.brd"
TYPE "%~dp0parrot.brd"
DEL "%~dp0parrot.brd"


:# Just a bit of animation
For /L %%i in (0 1 25)Do (
%$Cout% /Y 25 /X 19 /C random /B M /S ".{EQ}{DQ}-. "
%$Cout% /D 1 /X 17 /C random /B M /S "_{  '   ; "
%$Cout% /D 1 /X 15 /C random /B M /S ".~  `."
%$Cout% /R 1 /C random /B M /S ".'.^`~-. "
%$Cout% /D 1 /X 14 /C random /B M /S "{   '-."
%$Cout% /R 1 /C random /B M /S ".'.--~'`}"
%$Cout% /D 1 /X 15 /C random /B M /S "}.-~^'"
%$Cout% /R 1 /C random /B M /S "'-. '-..'  "
%$Cout% /D 1 /X 14 /C random /B M /S "{  -'.~('-._,.'"
%$Cout% /D 1 /X 15 /C random /B M /S "`--; ;  `.  ;"
%$Cout% /D 1 /X 19 /C random /B M /S "`-..__,-'"
%$Cout% /T 15 /Y 8 /X 26 /C random /B C /S }
%$Cout% /D 2 /R 5 /I 2
%$Cout% /U 1 /R 1 /C 33 /S \
%$Cout% /Y 25 /X 19 /C random /B M /S ".{EQ}{DQ}-. "
%$Cout% /D 1 /X 17 /C random /B M /S "_{  '   ; "
%$Cout% /D 1 /X 15 /C random /B M /S ".~  `."
%$Cout% /R 1 /C random /B M /S ".'.^`~-. "
%$Cout% /D 1 /X 14 /C random /B M /S "{   '-."
%$Cout% /R 1 /C random /B M /S ".'.--~'`}"
%$Cout% /D 1 /X 15 /C random /B M /S "}.-~^'"
%$Cout% /R 1 /C random /B M /S "'-. '-..'  "
%$Cout% /D 1 /X 14 /C random /B M /S "{  -'.~('-._,.'"
%$Cout% /D 1 /X 15 /C random /B M /S "`--; ;  `.  ;"
%$Cout% /D 1 /X 19 /C random /B M /S "`-..__,-'"
%$Cout% /T 15 /Y 8 /X 26 /C random /B B /S {EQ}
%$Cout% /D 2 /R 5 /Del 2
%$Cout% /U 1 /R 1 /C 33 /S "|"
If %%i EQU 25 %$Cout% /H + /Y 34 /X 1 /C 33 /S example 2 done /N
)


Goto :Eof

Parrot

Windows10((版本1511,版本10586,版本2015-11-10))支持 ANSI colors
您可以使用转义键来触发颜色代码。

在命令提示符中:

echo ^[[32m HI ^[[0m

回声 Ctrl + [[32m HI Ctrl + [[0mEnter

使用文本编辑器时,可以使用 ALT 键代码。
ESC 密钥代码可以使用 ALTNUMPAD编号创建: Alt + 027

[32m  HI  [0m

我会先给你们你们想要的答案,给那些不想看一大堆解释的人。

use 参数

@echo off
echo [38;2;255;255;0mHi[m [38;2;128;128;255mWorld[m
pause > nul

不要忘记输入 ESC0x1B (十六进制) ,033(十月) ,27(十二月) 虚钥码 VK _ ESCAPE

我建议您复制(以防遗漏 ESC 键)上述内容,然后将其粘贴到 记事本 + + 或其他您喜欢的 IDE 上。

output as below picture

enter image description here

解释

根据 ANSI_escape_code.SGR_parameters你知道

号码 姓名 注意 例子
0 Reset or normal 所有特征都消失了 ESC[0mESC[m
1 Bold or increased intensity ESC[1m
3 我用滑石粉 ESC[3m
4 下划线 ESC[4m
8 隐藏或 藏起来 没有得到广泛支持。 ESC[8m
30-37 设置前景色 30: 黑31: 红32: 绿33: 黄34: 蓝35: 紫36: 水37: 白 红色: ESC[31m
38 设置 前景颜色 下一个参数是5; n 或 2; r; g; b 红色: ESC[38m;2;255;0;0m
40-47 Set background color 红色: ESC [41米
48 设置 背景颜色 下一个参数是5; n 或 2; r; g; b 红色: ESC[48m;2;255;0;0m

当然,还有很多你可以去看。

比如说,

假代码 code (copy this to try by yourself) 小样
ESC[31mESC[4mfore color: red and style:underlineESC[0m echo [31m[4mfore color: red and style:underline[0m fore-color:red and underline
ESC[31mESC[4mfore color: red and style:underlineESC[0m
|       |                 |                   ------ 👉 Reset, such that the next one will not apply.
|       |  -----------------------------------
|       |  👉 input message
|       |
|    ------
|    👉 Underline
|
-------
👉 Set foreground color 31 is red

其中 ESC = 0x1B (因为在这里输入了 ESC,所以用户看不到它)

Script and Exercises

@echo off


:: demo: foreground color
for /l %%x in (30, 1, 37) do (
call :demoDefaultColor "COLOR" %%x
)


:: demo: background color
for /l %%x in (40, 1, 47) do (
call :demoDefaultColor "COLOR" %%x
)


call :echoWithColor "Hello world!" 255 0 0
echo Hello world!
call :echoWithColor "Hello world!" 255 0 255  255 255 0


pause > nul
EXIT /B




:demoDefaultColor <msg> <colorFlag>
echo [%2m%~1[0m
EXIT /B


:echoWithColor <msg> <fr> <fg> <fb> <br> <bg> <bb>
SET msg=%~1
SET fr=%2
SET fg=%3
SET fb=%4
SET br=%5
SET bg=%6
SET bb=%7


echo [48;2;%br%;%bg%;%bb%m[38;2;%fr%;%fg%;%fb%m%msg%[0m
EXIT /B

产出:

enter image description here