Batchography: Building a dynamic menu in Batch files – Part 1

batchography-good-resIn this blog post, I am going to share with you a recipe from the Batchography book that illustrates and explains how to build a dynamic menu using the CHOICE command with Batch files. In this article, we will dynamically build a menu around the COLOR command so that the user can change the colors of the console interactively.

To learn more about this technique and the Batch scripting language, please refer to Chapters 3 and 4 in the Batchography book.

flower separator

Get the book from Amazon: the print editionbtn-buy-on-amazonor the e-book editionbtn-buy-on-amazon

flower separator

The idea

The idea behind our script is to create an interactive Batch file that acts as a interface to the COLOR command line utility.

If you run the COLOR command with the “/?” switch, you get the following output:

Sets the default console foreground and background colors.

COLOR [attr]

  attr        Specifies color attribute of console output

Color attributes are specified by TWO hex digits -- the first
corresponds to the background; the second the foreground.  Each digit
can be any of the following values:

    0 = Black       8 = Gray
    1 = Blue        9 = Light Blue
    2 = Green       A = Light Green
    3 = Aqua        B = Light Aqua
    4 = Red         C = Light Red
    5 = Purple      D = Light Purple
    6 = Yellow      E = Light Yellow
    7 = White       F = Bright White

If no argument is given, this command restores the color to what it was
when CMD.EXE started.  This value either comes from the current console
window, the /T command line switch or from the DefaultColor registry
value.

The COLOR command sets ERRORLEVEL to 1 if an attempt is made to execute
the COLOR command with a foreground and background color that are the
same.

Example: "COLOR fc" produces light red on bright white

Therefore, it is evident that if you type:

COLOR 07

Then you will get the black background with the white foreground colors, and so on.

The “console-color.bat” utility that we want to write will look like this:

batchography-dyn-menu-1

As you can see from the screenshot above, the interactive elements of the script are:

  1. An informative message showing the color numbers and names
  2. A prompt asking the user to enter the colors and ensuring that only valid color numbers are presented
  3. A quit functionality to abort the interactive script

The logic of this script breaks down into the following steps:

  1. Run the “COLOR /?” command, capture and parse the output
  2. Build an associative array with the color names and numbers
  3. Display the color names and numbers to the screen and then interactively prompt the user to enter the colors
  4. Change the console colors
  5. Repeat the steps 3 to 4 until the user presses “Q”

Let’s write the script

I am not going to go into all the details about the Batch syntax, instead I will just focus on the most important aspects.

To learn in more details how everything works, there is no better excuse than reading the Batchography book.

Parsing the color names

In order to display just the color numbers and names, we will need to invoke the “COLOR /?” command and pipe the output to FINDSTR and a regular expression to filter out all the lines except for the COLOR lines:

:: Displays all the available colors and their names
:display-colors-numbers
  color /? | findstr /r /C:"[0-9a-f] = "
  exit /b 0

The regular expression “[0-9a-f] = ” will ensure that only lines of the form: “ColorNumber = ” will be captured.

C:\Batchography>color /? | findstr /r /C:"[0-9a-f] = "
    0 = Black       8 = Gray
    1 = Blue        9 = Light Blue
    2 = Green       A = Light Green
    3 = Aqua        B = Light Aqua
    4 = Red         C = Light Red
    5 = Purple      D = Light Purple
    6 = Yellow      E = Light Yellow
    7 = White       F = Bright White

C:\Batchography>

Building the data structures to represent the colors

Now we need to have a table linking the color numbers (0 to F) to their corresponding names. This will serve two purposes: the first is to be able to build the proper CHOICE prompt and the second to print nice messages when the user changes the colors.

The “get-colors-array” function below will create the associative array that maps a color number to its name:

:: Returns an associative array linking the color number to its name
:get-colors-array <1=out-array>
  for /f "usebackq tokens=*" %%a in (`color /? ^| findstr /r /C:"[0-9a-f] = "`) do (
    for /f "tokens=1,2,3* delims== " %%b in ("%%a") do (
      set %1.%%b=%%c
      set %1.%%d=%%e
    )
  )
  goto :eof

The output of “COLOR /?” is passed to FINDSTR and then is tokenized using two nested “FOR /F” loops.

Note: Please refer to Chapter 2 to learn more about FOR loops/tokenizing and to Chapter 3 in the Batchography book to learn more about data structures.

The next needed piece of information is a single long string containing the all the choice letters. We will pass this string to the CHOICE command with the “/C:” switch.

The following are two supporting functions:

:: Returns all the color numbers
:get-colors-numbers <1=letters>
  setlocal
  set t=
  for /f "usebackq" %%a in (`call "%~f0" print-colors ^| sort`) do (
    set t=!t!%%a
  )
  (
    endlocal
    set %~1=%t%
  )
  goto :eof


:: Display all the color numbers (one color number per line)
:print-color-numbers
  for /f "usebackq tokens=*" %%a in (`color /? ^| findstr /r /C:"[0-9a-f] = "`) do (
    for /f "tokens=1,2,3,4 delims== " %%b in ("%%a") do (
      echo %%b
      echo %%d
    )
  )
  goto :eof

The “print-color-numbers” function invokes the “COLOR /?” command and breaks down the two column output into a single column. This is essential in order to be able to sort the color numbers in ascending order.

The “get-colors-numbers” function will make use of the “print-color-numbers” function and sort the color numbers then concatenate all of them into a single variable.

Putting it altogether

Now we have all the support functions, we can put everything together in the main function of the Batch script like this:

setlocal enabledelayedexpansion

title Dynamic menu example - changing console colors interactively

:main
  if "%1"=="print-colors" (
    call :print-color-numbers
    exit /b 0
  )

  call :get-colors-array colors
  :repeat-1
    cls
  
    echo Color names and numbers:
    echo.
    call :display-colors-numbers
    call :get-colors-numbers letters
    set letters=Q%letters%
    
    echo.
    set /p =Enter the foreground followed by the background color number (or press Q to quit): <nul

    :: Select foreground color
    choice /c:%letters% > nul
    set /a fg=%errorlevel%-1
    if %fg%==0 goto break-1
    call set fg=%%letters:~%fg%,1%%
    set /p=%fg% <nul

    :: Select the background color
    choice /c:%letters% > nul
    set /a bg=%errorlevel%-1
    if %bg%==0 goto break-1
    call set bg=%%letters:~%bg%,1%%
    echo %bg%


    call set msg=Changing colors to %%colors.%fg%%% on %%colors.%bg%%%
    set /p "=%msg%" <nul
    for /l %%a in (1,1,3) do (
      timeout /t 1 >nul
      set /p=.<nul
    )
    color %bg%%fg%
    echo.
    goto :repeat-1
  :break-1

  goto :eof

The takeaways from the main function are:

  1. Enable delayed environment variables expansion
  2. Change the console title. This is a nice thing to do in interactive scripts such as this one.
  3. Build the color numbers/color names associative array once
  4. Display the color numbers and names
  5. Prompt the user (on the same line) so s/he enters two color number values.
    1. Use the CHOICE utility
    2. Check if the “Q” key is pressed and quit
    3. Convert the choice result number (%errorlevel%) to an actual color value (use substrings)
  6. Display the foreground and background colors that will be displayed, wait 3 seconds, then change the console color

Download the script

You may download the full source code of the script from the Batchography GitHub repository:

Download
console-color.bat

The Batch scripting language is fairly powerful and if used correctly, it can elegantly solve simple to intermediate automation problems. I hope you found this script useful. There is a lot to learn and discover, the Batchography book is a good comprehensive guide for that.
flower separatorYou might also like:

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.