Search code examples
windowsbatch-filecolorscharacter-encodingcmd

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.


Solution

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