In 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.
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:
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:
As you can see from the screenshot above, the interactive elements of the script are:
- An informative message showing the color numbers and names
- A prompt asking the user to enter the colors and ensuring that only valid color numbers are presented
- A quit functionality to abort the interactive script
The logic of this script breaks down into the following steps:
- Run the “COLOR /?” command, capture and parse the output
- Build an associative array with the color names and numbers
- Display the color names and numbers to the screen and then interactively prompt the user to enter the colors
- Change the console colors
- 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:
- Enable delayed environment variables expansion
- Change the console title. This is a nice thing to do in interactive scripts such as this one.
- Build the color numbers/color names associative array once
- Display the color numbers and names
- Prompt the user (on the same line) so s/he enters two color number values.
- Use the CHOICE utility
- Check if the “Q” key is pressed and quit
- Convert the choice result number (%errorlevel%) to an actual color value (use substrings)
- 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:
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.
You might also like:
- Batchography: Embedding an executable file in a Batch script
- WifiPasswordReveal: A script to reveal all the saved WiFi passwords in Windows 7 and above
- My books
- Free pictures to PDF converter: Pic2Pdf v1.0
- Introducing the “Batchography: The Art of Batch Files Programming” book