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.


ANSWERS:


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

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.


Without external tools.This is a self-compiled bat/.net hybrid (should be saved as .BAT) that can be used on any system that have installed .net framework (it's a rare thing to see an windows without .NET framework even for the oldest XP/2003 installations) . It uses jscript.net compiler to create an exe capable to print strings with different background/foreground color only for the current line.

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

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

You can also check carlos' color function ->


If your console supports ANSI colour codes (e.g. ConEmu, Clink or ANSICON) you can do this:

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

where ESC variable contains ASCII character 27.

I found a way to populate the ESC variable here: and using tasklist it's possible to test what DLLs are loaded into a process.

The following script gets the process ID of the cmd.exe that the script is running in. Checks if it has a dll that will add ANSI support injected, and then sets colour variables to contain escape sequences or be empty depending on whether colour is supported or not.

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

Just to complete this topic, you may also show text in color using my ColorShow.exe auxiliary program; you may download it from this site, look for program #12. Please note that the first part of the documentation appear in program #2-Show.exe.

There are several auxiliary programs at that site that allows to achieve some interesting things. For example, program #6-CursorPos.exe allows to move the cursor to any place in the screen.

This is an output example produced by a Batch file using my ColorShow.exe auxiliary program:

Mona-Lisa

The Batch file took less than 3 seconds to show previous image, that have a resolution of 322x138 (using Lucida Console font @ size 5). You may review the method used to produce this image at this post.

EDIT: I posted a much simpler method to get ColorShow.exe program and a brief description of it; just follow this link.


Combining dbenham's bird and syntax with skrebbel's powershell write-host method, it seems that powershell can render complex art more quickly than dbenham's pure batch method (well, after powershell has been primed once, anyway). Minimal massaging of the strings are needed, although I haven't tested this with anything other than the bird. If you want a bright green end-of-transmission character for example, you may be out of luck. :)

This method requires echoing out to a temp file, simply because invoking powershell for each call :c takes forever, and it's much faster to queue the output for one powershell invocation. But it does have the advantage of simplicity and efficiency.

@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

Result:

enter image description here


Yes, it is possible with cmdcolor:

echo \033[32mhi \033[92mworld

hi will be dark green, and world - light green.


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

If you have a modern Windows (that has powershell installed), the following may work fine as well

call :PrintBright Something Something

  (do actual batch stuff here)

call :PrintBright Done!
goto :eof


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

Adjust the color as you see fit.


All alternatives described thus far use any temporary files. This is bad, it is not always possible to use temporary files. This script below uses no temporary file and can write text on any screen position. The best script for this purpose is this


Several methods are covered in
"51} How can I echo lines in different colors in NT scripts?"


One of the alternatives: If you can get hold of QBASIC, using colors is relatively easy:

  @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

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.


You should download chgcolor.zip from and also download echoj.zip from www.mailsend-online.com/blog/?p=41 They're both towards the bottom of the page. Extract both folders to the desktop and copy the executables(.exe files) from inside the extracted folders to the C:\Windows directory. This will allow them to be executed from the command line. Open up notepad and copy the following into it:

@echo off

chgcolor 03

echoj "hi "

chgcolor 0d

echoj "world"

chgcolor 07

echoj $0a

Save the file to the Desktop as hi.bat. Now open the command prompt and navigate to your Desktop folder and type "hi.bat" without the quotes. That should get you started besure to read both webpages to get a full tutorial.


Unless you are using an older operating system this is I believe not possible to do with the commands available to you.

However all is not lost, have a look at this page:

This will give you exactly what you need, the down side though is that you need to add the utilities on that page.



 MORE:


 ? How to have multiple colors in a Windows batch file?
 ? How to have multiple colors in a Windows batch file?
 ? Need help on multi-colored batch chat
 ? Change text colour in WINDOWS command line
 ? Color echo in batch files
 ? (BATCH) Multiple colors on one line
 ? Why are my special characters not ignored in Quoted Batch?
 ? What are the undocumented features and limitations of the Windows FINDSTR command?
 ? How can i change the colour of a command window via batch script when using the start command
 ? Split batch file commands into multiple lines in Windows