How to have multiple colors in a Windows batch file? How to have multiple colors in a Windows batch file? windows windows

How to have multiple colors in a Windows batch file?


You can do multicolor outputs without any external programs.

@echo offSETLOCAL EnableDelayedExpansionfor /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 readcall :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:ColorTextecho off<nul set /p ".=%DEL%" > "%~2"findstr /v /a:%1 /R "^$" "%~2" nuldel "%~2" > nul 2>&1goto :eof

It uses the color feature of the findstr command.

Findstr can be configured to output line numbers or filenames in a defined color.
So I first create a file with the text as filename, and the content is a single <backspace> character (ASCII 8).
Then I search all non empty lines in the file and in nul, so the filename will be output in the correct color appended with a colon, but the colon is immediatly removed by the <backspace>.

EDIT: One year later ... all characters are valid

@echo offsetlocal EnableDelayedExpansionfor /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:colorset "param=^%~2" !set "param=!param:"=\"!"findstr /p /A:%1 "." "!param!\..\X" nul<nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"exit /b

This uses the rule for valid path/filenames.
If a \..\ is in the path the prefixed elemet will be removed completly and it's not necessary that this element contains only valid filename characters.


jeb's edited answer comes close to solving all the issues. But it has problems with the following strings:

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

I've modified his technique to something that I think can truly handle any string of printable characters, except for length limitations.

Other improvements:

  • Uses the %TEMP% location for the temp file, so no longer need write access to the current directory.

  • Created 2 variants, one takes a string literal, the other the name of a variable containing the string. The variable version is generally less convenient, but it eliminates some special character escape issues.

  • Added the /n option as an optional 3rd parameter to append a newline at the end of the output.

Backspace does not work across a line break, so the technique can have problems if the line wraps. For example, printing a string with length between 74 - 79 will not work properly if the console has a line width of 80.

@echo offsetlocalcall :initColorPrintcall :colorPrint 0a "a"call :colorPrint 0b "b"set "txt=^" & call :colorPrintVar 0c txtcall :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:" /necho(set complex="c:\hello world!/.\..\\a//^<%%>&|!" /^^^<%%^>^&^|!\call :colorPrintVar 74 complex /ncall :cleanupColorPrintexit /b::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::colorPrint Color  Str  [/n]setlocalset "str=%~2"call :colorPrintVar %1 str %3exit /b:colorPrintVar  Color  StrVar  [/n]if not defined %~2 exit /bsetlocal enableDelayedExpansionset "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" nulif /i "%~3"=="/n" echo(exit /b:initColorPrintfor /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:cleanupColorPrintdel "%temp%\x"exit /b


UPDATE 2012-11-27

This method fails on XP because FINDSTR displays backspace as a period on the screen. jeb's original answer works on XP, albeit with the limitations already noted


UPDATE 2012-12-14

There has been a lot of development activity at DosTips and SS64. It turns out that FINDSTR also corrupts file names containing extended ASCII if supplied on the command line. I've updated my FINDSTR Q&A.

Below is a version that works on XP and supports ALL single byte characters except 0x00 (nul), 0x0A (linefeed), and 0x0D (carriage return). However, when running on XP, most control characters will display as dots. This is an inherent feature of FINDSTR on XP that cannot be avoided.

Unfortunately, adding support for XP and for extended ASCII characters slows the routine down :-(

Just for fun, I grabbed some color ASCII art from joan stark's ASCII Art Gallery and adapted it for use with ColorPrint. I added a :c entry point just for shorthand, and to handle an issue with quote literals.

@echo offsetlocal disableDelayedExpansionset q=^"echo(echo(call :c 0E "                ,      .-;" /ncall :c 0E "             ,  |\    / /  __," /ncall :c 0E "             |\ '.`-.|  |.'.-'" /ncall :c 0E "              \`'-:  `; : /" /ncall :c 0E "               `-._'.  \'|" /ncall :c 0E "              ,_.-=` ` `  ~,_" /ncall :c 0E "               '--,.    "&call :c 0c ".-. "&call :c 0E ",=!q!." /ncall :c 0E "                 /     "&call :c 0c "{ "&call :c 0A "* "&call :c 0c ")"&call :c 0E "`"&call :c 06 ";-."&call :c 0E "}" /ncall :c 0E "                 |      "&call :c 0c "'-' "&call :c 06 "/__ |" /ncall :c 0E "                 /          "&call :c 06 "\_,\|" /ncall :c 0E "                 |          (" /ncall :c 0E "             "&call :c 0c "__ "&call :c 0E "/ '          \" /ncall :c 02 "     /\_    "&call :c 0c "/,'`"&call :c 0E "|     '   "&call :c 0c ".-~!q!~~-." /ncall :c 02 "     |`.\_ "&call :c 0c "|   "&call :c 0E "/  ' ,    "&call :c 0c "/        \" /ncall :c 02 "   _/  `, \"&call :c 0c "|  "&call :c 0E "; ,     . "&call :c 0c "|  ,  '  . |" /ncall :c 02 "   \   `,  "&call :c 0c "|  "&call :c 0E "|  ,  ,   "&call :c 0c "|  :  ;  : |" /ncall :c 02 "   _\  `,  "&call :c 0c "\  "&call :c 0E "|.     ,  "&call :c 0c "|  |  |  | |" /ncall :c 02 "   \`  `.   "&call :c 0c "\ "&call :c 0E "|   '     "&call :c 0A "|"&call :c 0c "\_|-'|_,'\|" /ncall :c 02 "   _\   `,   "&call :c 0A "`"&call :c 0E "\  '  . ' "&call :c 0A "| |  | |  |           "&call :c 02 "__" /ncall :c 02 "   \     `,   "&call :c 0E "| ,  '    "&call :c 0A "|_/'-|_\_/     "&call :c 02 "__ ,-;` /" /ncall :c 02 "    \    `,    "&call :c 0E "\ .  , ' .| | | | |   "&call :c 02 "_/' ` _=`|" /ncall :c 02 "     `\    `,   "&call :c 0E "\     ,  | | | | |"&call :c 02 "_/'   .=!q!  /" /ncall :c 02 "     \`     `,   "&call :c 0E "`\      \/|,| ;"&call :c 02 "/'   .=!q!    |" /ncall :c 02 "      \      `,    "&call :c 0E "`\' ,  | ; "&call :c 02 "/'    =!q!    _/" /ncall :c 02 "       `\     `,  "&call :c 05 ".-!q!!q!-. "&call :c 0E "': "&call :c 02 "/'    =!q!     /" /ncall :c 02 "    jgs _`\    ;"&call :c 05 "_{  '   ; "&call :c 02 "/'    =!q!      /" /ncall :c 02 "       _\`-/__"&call :c 05 ".~  `."&call :c 07 "8"&call :c 05 ".'.!q!`~-. "&call :c 02 "=!q!     _,/" /ncall :c 02 "    __\      "&call :c 05 "{   '-."&call :c 07 "|"&call :c 05 ".'.--~'`}"&call :c 02 "    _/" /ncall :c 02 "    \    .=!q!` "&call :c 05 "}.-~!q!'"&call :c 0D "u"&call :c 05 "'-. '-..'  "&call :c 02 "__/" /ncall :c 02 "   _/  .!q!    "&call :c 05 "{  -'.~('-._,.'"&call :c 02 "\_,/" /ncall :c 02 "  /  .!q!    _/'"&call :c 05 "`--; ;  `.  ;" /ncall :c 02 "   .=!q!  _/'      "&call :c 05 "`-..__,-'" /ncall :c 02 "    __/'" /necho(exit /b:csetlocal enableDelayedExpansion::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::colorPrint Color  Str  [/n]setlocalset "s=%~2"call :colorPrintVar %1 s %3exit /b:colorPrintVar  Color  StrVar  [/n]if not defined DEL call :initColorPrintsetlocal enableDelayedExpansionpushd .':cd \set "s=!%~2!":: The single blank line within the following IN() clause is critical - DO NOT REMOVEfor %%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(popdexit /b:initColorPrintfor /f %%A in ('"prompt $H&for %%B in (1) do rem"') do set "DEL=%%A %%A"<nul >"%temp%\'" set /p "=."subst ': "%temp%" >nulexit /b:cleanupColorPrint2>nul del "%temp%\'"2>nul del "%temp%\colorPrint.txt">nul subst ': /dexit /b


Actually this can be done without creating a temporary file.The method described by jeb and dbenham will work even with a target file that contains no backspaces. The critical point is that the line recognized by findstr.exe must not end with a 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!Here's an updated example script working this way...

Changes from the previous example:

  • Uses a single dash on the last line as the searchable string. (Must be short and not appear anywhere else like this in the batch.)
  • Renamed routines and variables to be a little more object-oriented :-)
  • Removed one call level, to slightly improve performance.
  • Added comments (Beginning with :# to look more like most other scripting languages.)

@echo offsetlocalcall :Echo.Color.Initgoto main:Echo.Color %1=Color %2=Str [%3=/n]setlocal enableDelayedExpansionset "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!" nulpopd:# 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 CRLFif not "%~3"=="" echo.endlocal & goto :eof:Echo.Color.Var %1=Color %2=StrVar [%3=/n]if not defined %~2 goto :eofsetlocal enableDelayedExpansionset "str=!%~2!"goto :Echo.Color.2:Echo.Color.Initset "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:maincall :Echo.Color 0a "a"call :Echo.Color 0b "b"set "txt=^" & call :Echo.Color.Var 0c txtcall :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:" /necho(set complex="c:\hello world!/.\..\\a//^<%%>&|!" /^^^<%%^>^&^|!\call :Echo.Color.Var 74 complex /nexit /b:# The following line must be last and not end by a CRLF.-

PS. I'm having a problem with the output of the ! character that you did not have in the previous example. (Or at least you did not have the same symptoms.) To be investigated.