Introduction
Back in 2016, I decided to learn as much as I can about the Batch files programming language because Batch was my first programming language when I was a kid. Today I share with you some of those Batchography tips.
Background
If you have done some basic command prompt work (cmd.exe) and/or have written basic Batch files, then please skip this section.
If you have never done Batch files programming, then welcome. Just run "cmd.exe" to open the command prompt, then type: "notepad hello.bat
".
In Notepad, just type the following:
@echo off
echo Welcome to the Batch Programming World!
Close Notepad and save the file. Now back to the command prompt, type: "hello.bat" and hit the ENTER key.
That's it! That was your first Batch file script which outputs the message from above.
It is advisable that you know some programming concepts to proceed with the remainder of this article.
Trick #1 - Taking user input and doing arithmetic operations
Often times, it is very important to write interactive scripts that take input from the user and carry arithmetic operations if needed.
To read user input, we can use the following syntax:
SET /P VarName=The prompt text
So for example, to ask the user for his/her name and display it back again, we can do the following:
@echo off
setlocal
SET /P Name="What is your name? "
echo Welcome %Name%
Quote:
It is important not to pollute the environment variables namespace when using the "SET" command and therefore it is a good practice to start your script with the "setlocal" command that will revert the environment variable changes when the script terminates.
Similarily, to do arithmetic operations, we can use the following syntax:
SET /A Number=Expression
For example:
SET /A Number=1+2+3+4
Would compute into the variable "Number" the value "10".
Now, we can combine those two tricks to create a small integer expression calculator:
@echo off
setlocal
:repeat
SET /P Expr="Please enter an expression (or 'q') to quit:"
SET /A Result=%Expr%
if "%Expr%"=="" goto :eof
if "%Expr%"=="q" goto :eof
echo The result is %Result%
goto repeat
Here's a sample output from this script:
C:\Temp\Batchography>expr-calc.bat
Please enter an expression (or 'q') to quit:1+2+3
The result is 6
Please enter an expression (or 'q') to quit:-5+2
The result is -3
Please enter an expression (or 'q') to quit:q
C:\Temp\Batchography>
Trick #2 - Number counting
Number counting can come in handy in many scenarios. It could be used to create numbered dummy folders, write an algorithm that requires counting, or anything else you can think of.
In Batch files, to count, you can use the following syntax:
FOR /L %variable IN (start, step, end) DO command [command-parameters]
Let's illustrate by writing a small script that creates 10 dummy folders: "folder1" to "folder10":
So let's assume we have the following files:
@echo off
for /L %%a in (1, 1, 10) do (
mkdir folder%%a
)
For example, let us write the sigma function (do the addition from 1 to N):
@echo off
setlocal
:repeat
SET /P N="Please N for the sigma computation:"
SET /A Result=0
for /L %%i in (1, 1, %N%) do (
SET /A Result=Result+%%i
)
echo Sigma(%N%)=%Result%
Trick #3 - Reading a text file line by line in Batch files
Reading from a text file, one line at a time can be very handy for text scanning and transformation. Use the "FOR /F" syntax like this:
@echo off
for /f "delims=" %%a in (the-file.txt) DO (
ECHO Line is: %%a
)
We can implement a very basic non-empty lines counter in text files using the Batch language like this:
@echo off
setlocal enabledelayedexpansion
if "%1"=="" (
echo Please specify a file name!
goto :eof
)
set /A nlines=0
for /f "delims=" %%a in (%1) DO (
set /A nlines+=1
)
echo Total non-empty lines: %nlines%
Quote:
The "FOR /F" will skip empty lines in input text files.
Trick #4 - String substitution
With the Batch scripting language, it is possible to do string substitution. To achieve that, we have to have the string in question inside an environment variable. We can then use the following syntax:
%VarName:StringToBeMatched=StringToBeReplacedWith%
Let's write an interactive script that replaces the word "books" with "ebooks" in the file "email.txt":
Reading books was the norm during his grandfather's time.
People used to carry books with them to school in order to read and study.
Some say that books will become obsolete one day. Who knows.
The following script will do the string substitution and generate a new file called "new-email.txt":
@echo off
setlocal enabledelayedexpansion
if exist new-email.txt del new-email.txt
for /f "delims=" %%a in (email.txt) DO (
set line=%%a
echo !line:books=ebooks! >>new-email.txt
)
Quote:
We use the "setlocal enabledelayedexpansion" and the "!Var!" syntax instead of "%Var%" syntax when we are expanding variables from inside compound statements.
The "new-email.txt" contents are:
Reading ebooks was the norm during his grandfather's time.
People used to carry ebooks with them to school in order to read and study.
Some say that ebooks will become obsolete one day. Who knows.
Trick #5 - Polyglot scripts: Mixing Python and Batch files
A very fun trick is when we can have a script that runs successfully under two or more languages. Let's illustrate how to do a mixed script for running Python and Batch files:
@echo off
rem = """
:: From here and on, write any Batch file syntax and it will be ignored by Python
::
:: The Batchography book by Elias Bachaalany
::
python -x "%~f0" %*
exit /b %errorlevel%
:: End of batch file commands
"""
# Anything here is interpreted by Python
import platform
import sys
print("Hello world from Python %s!\n" % platform.python_version())
print("The passed arguments are: %s" % sys.argv[1:])
The above is a Batch script that invokes itself again as a Python script using the "python -x" switch (skip the first line).
Such scripts is useful when you first want a Batch script to set up or verify the right environment before invoking its embedded Python code.
Trick #6 - Polyglot scripts: A self-compiling C++ and Batch file
Similar to Trick #5, we can make a Batch file script that is also a C++ program. Here's how we can make a self-compiling C++ Batch script:
#include <stdio.h>
int main()
{
printf(
"Hello world! I was self-compiled!\n"
"\n"
"Checkout the Batchography book!\n");
return 0;
}
There's a slight drawback in this polyglot script. The first line ("/*" a C multi-line comment opening) is not a valid command and it will cause an error but we redirect the error to the nul device. We close the multi-line comment (with "*/") shortly after exiting the Batch file.
Trick #7 - Tokenizing commands output
It is possible to execute a command then break its output into tokens. To achieve this, we will use the "FOR /F" syntax.
From the command prompt, to query the registry and retrieve the language ID, we can use the "reg.exe" command like such:
C:\Temp\Batchography>reg query "hklm\system\controlset001\control\nls\language" /v Installlanguage
HKEY_LOCAL_MACHINE\system\controlset001\control\nls\language
Installlanguage REG_SZ 0409
C:\Temp\Batchography>
We have two lines output. We only care about the second line and the 3rd token (if we tokenize the string using the space character). To retrieve the 0409 value and write a Batch script to detect the system language, we can do the following:
@echo off
for /F "usebackq tokens=3" %%a IN (`reg query "hklm\system\controlset001\control\nls\language" /v Installlanguage`) DO (
set lang_id=%%a
)
:: 0409 English ; 0407 German ; 040C French ; 0C0A Spanish
if "%lang_id%"=="0409" (
echo English detected
) else if "%lang_id%" == "040C" (
echo French detected
) else (
echo Note: Unknown language ID %lang_id%!
)
The Batch script above, filters for lines that have at least 3 tokens and it captures the first token only.
Trick #8 - Functions are fun
Who said the Batch language is a simple language? Did you know that you can write functions (even recursive ones)?
To define a function, simply create a label and then call it:
@echo off
setlocal
:main
echo Hello!
set /p a=Enter the first number:
set /p b=Enter thne second number:
call :add result %a% %b%
echo The result is: %result%
goto :eof
:add <1=return var> <2=first number> <3=second number>
echo Adding '%2' and '%3'. Returning the result into the variable '%1'
set /a %1=%2+%3
goto :eof
The function "add", is just a label and what comes after it in the same line are ignored / free text. As a convention, we put the argument number and its description. The "add" function is defined to take a return variable name (argument #1) and two numbers "a" (argument #2) and "b" (argument #3).
The "main" function calls "add" using the "call :func_name" syntax and passing the arguments thereafter. When "add" returns, it may call "goto :eof" or "exit /b <return_code>".
Conclusion
The Batch programming is an old but a beautiful language. It has so many features that I was delighted to research and learn about.