Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have multiple colors in a Windows batch file?

I was wondering if its possible to have different colored text on the same line in a Windows batch file, for example if it says

echo hi world 

I want "hi" to be one color, and "world" to be another color. Maybe I could set the COLOR command as a variable:

set color1= color 2 set color9= color A 

and then deploy them both on the same line along with

echo hi world 

but I don't know how I would do that.

like image 443
daniel11 Avatar asked Dec 02 '10 20:12

daniel11


People also ask

What is %% in a batch file?

Use double percent signs ( %% ) to carry out the for command within a batch file. Variables are case sensitive, and they must be represented with an alphabetical value such as %a, %b, or %c. ( <set> ) Required. Specifies one or more files, directories, or text strings, or a range of values on which to run the command.

Can CMD display colors?

Color is an inbuilt command found inside the Windows Command Processor (cmd.exe), that is used for changing the colors for the console's foreground and background. By default, the console has white foreground color and black background color (07 color code).

How do I make text color in CMD?

To set the default Command Prompt window color, select the upper-left corner of the Command Prompt window, select Defaults, select the Colors tab, and then select the colors that you want to use for the Screen Text and Screen Background.


2 Answers

You can do multicolor outputs without any external programs.

@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 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 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 

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.

like image 115
jeb Avatar answered Oct 11 '22 12:10

jeb


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 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 


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 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 
like image 22
dbenham Avatar answered Oct 11 '22 14:10

dbenham