Windows Batch

Windows batch scripting

TOC

Arguments

Arg %1 Arg %z Content
%1 %%~x expand %1 to a drive letter and path only
%~n1 %%~nz filename without the extension
%~x1 %%~xz extension of the file
%~nx1 %%~nxz filename with extension
%~dp1 %%~dpz path to the file
%~dp0 path to the cmd file itself (zero arg is the cmd file itself)
%~f1 fully qualified path name
%~d1 drive letter only
%~1 expand %1 removing any surrounding quotes
%~a1 the file attributes of %1
%~t1 the date/time of %1
%~z1 the file size of %1
%~s1 change the meaning of f, n, s and x to reference the Short 8.3 name (if it exists)
%~sp1 expand %1 to a path shortened to 8.3 characters
%* all arguments line

example:

for %%x in (%*) do (
   set /A argCount+=1
   REM argument x file name
   set "argVec[!argCount!]=%%~x" 
   REM argument x name without file extension
   set "argVn[!argCount!]=%%~nx" 
)

Variables

Decorators

%A vs %a vs \A** when used in batch files
Variables are case sensitive

Init

set /A myVar = 1

Assing the numerical value to myVar
/A is the switch used if the value needs to be numeric

Usage

@echo off 
set message=Hello World 
echo %message%

To display the value of the variable, note that the variable needs to be enclosed in the % sign

SET /A a = 5 
SET /A b = 10 
SET /A c = %a% + %b% 
echo %c%

The scope

Global vs local

By default, variables are global to your entire command prompt session. Call the SETLOCAL command to make variables local to the scope of your script. After calling SETLOCAL, any variable assignments revert upon calling ENDLOCAL, calling EXIT, or when execution reaches the end of file (EOF) in your script.

Environment variables

If you have variables that would be used across batch files, then it is always preferable to use environment variables. Once the environment variable is defined, it can be accessed via the % sign.

Arrays

Creating

Creating an array

set a[0]=1

From a list

@echo off 
set list=1 2 3 4 
(for %%a in (%list%) do ( 
   echo %%a 
))

Iterating

@echo off 
setlocal enabledelayedexpansion 
set topic[0]=comments 
set topic[1]=variables 
set topic[2]=Arrays 
set topic[3]=Decision making 
set topic[4]=Time and date 
set topic[5]=Operators 

for /l %%n in (0,1,5) do ( 
   echo !topic[%%n]! 
)

Length

The length of an array is done by iterating over the list of values in the array since there is no direct function to determine the number of elements in an array.

Structures

@echo off 
set obj[0].Name=Joe 
set obj[0].ID=1 
set obj[1].Name=Mark 
set obj[1].ID=2 
set obj[2].Name=Mohan 
set obj[2].ID=3 
FOR /L %%i IN (0 1 2) DO  (
   call echo Name = %%obj[%%i].Name%%
   call echo Value = %%obj[%%i].ID%%
)

We are able to access each element of the structure using the obj[%i%] notation

Lists

The "elements" in list can be delimited (separated) by spaces, tabs, commas or semicolons.
In NT, it is possible to define your own delimiters with FOR /F

Date and Time

System variables

@echo off 
echo %DATE%
echo %TIME%

Formatting

@echo off 
echo/Today is: %year%-%month%-%day% 
goto :EOF 
setlocal ENABLEEXTENSIONS 
set t = 2&if "%date%z" LSS "A" set t = 1 

for /f "skip=1 tokens = 2-4 delims = (-)" %%a in ('echo/^|date') do ( 
   for /f "tokens = %t%-4 delims=.-/ " %%d in ('date/t') do ( 
      set %%a=%%d&set %%b=%%e&set %%c=%%f)) 
endlocal&set %1=%yy%&set %2=%mm%&set %3=%dd%&goto :EOF

Loops

Source

FOR %variable IN (set) DO command [command-parameters]
%variable Specifies a replaceable parameter
(set) Specifies a set of one or more files. Wildcards may be used
command Specifies the command to carry out for each file
command-parameters Specifies parameters or switches for the specified command

By default command extensions are enabled. However, to be absolutely sure that they are, either use SETLOCAL ENABLEEXTENSIONS within your batch files or execute those scripts using CMD /X. Likewise, you may disable command extensions using SETLOCAL DISABLEEXTENSIONS or CMD /Y.
If Command Extensions are enabled, the following additional forms of the FOR command are supported

Note!
Keep in mind that in a FOR loop, the entire range (0..12345678 for the example) will be stepped through, even if the loop is "broken" halfway and nothing will be done inside the loop anymore.

filenameset is one or more file names.
Each file is opened, read and processed before going on to the next file in filenameset.
Processing consists of reading in the file, breaking it up into individual lines of text and then parsing each line into zero or more tokens. The body of the for loop is then called with the variable value(s) set to the found token string(s).
By default, /F passes the first blank separated token from each line of each file.
Blank lines are skipped.
You can override the default parsing behaviour by specifying the optional "options" parameter. This is a quoted string which contains one or more keywords to specify different parsing parameters.
The keywords are:

eol=c specifies an end of line comment character (just one)
Note: The default eol character is the semicolon ;. That is why FOR /F loops skip lines starting with semicolons unless a different eol character is specified (try "eol=")
skip=n specifies the number of lines to skip at the beginning of the file
delims=xxx specifies a delimiter set. This replaces the default delimiter set of space and tab
tokens=x,y,m-n specifies which tokens from each line are to be passed to the for body for each iteration
This will cause additional variable names to be allocated. The m-n form is a range, specifying the mth through the nth tokens.
If the last character in the tokens= string is an asterisk (*), then an additional variable is allocated and receives the remaining text on the line after the last token parsed
usebackq specifies that the new semantics are in force, where a back quoted string is executed as a command and a single quoted string is a literal string command and allows the use of double quotes to quote file names in filenameset

My usage

This is my own practical working example. I haven't used usebackq option, cause I didn't figured it out yet. But this is the reason the command line is inside both the single and double quotes.
But what I figured that I had to use !..! decoration to get the values in this code block, perhaps because it's inside another loop and the enabledelayedexpansion option is active.

SET /A "pWidth=0"
FOR /F "tokens=*" %%G IN ('""%ffpath%exiftool.exe" -b "!argVec[%%i]!" -ImageWidth"') DO SET /A pWidth=%%G

ECHO Image dimensions: !pHeight! by !pWidth!

Tokens and Delims

The general syntax of FOR /F commands is:

FOR /F "tokens=n,m* delims=ccc" %%A IN ('some_command') DO other_command %%A %%B %%C

Tokens are the numbers of the items in the list, that divided into tokens by the delimiter

Example:

FOR /F "tokens=2,3 delims= " %%A IN ('PING -a %1') DO IF "%%B"=="[%1]" SET PC=%%A

Very useful info in delimiters and tokens

String operations

Batch scripts have the following commands which are used to carry out string manipulation in strings.

%variable:~num_chars_to_skip% 
%variable:~num_chars_to_skip,num_chars_to_keep%

This can include negative numbers −

%variable:~num_chars_to_skip,-num_chars_to_keep%
%variable:~-num_chars_to_skip,num_chars_to_keep%
%variable:~-num_chars_to_skip,-num_chars_to_keep%
rem select from after the underscore to the end
set string=Abc_123
echo %string%
>> Abc_123
echo %string:~4,3%
>> 123

rem select from after the underscore to the end
for /f "tokens=2 delims=_" %%a in ("%STRING%") do (
  set AFTER_UNDERSCORE=%%a
)


set var1=Abc_123
rem select from after the underscore to the end
set var2=%var1:*_=%
echo %var2%

Echo into the same line

echo|set /p ="Executing backup...."
echo|set /p =" backup procedure"

ESC sequences

Colors and styles

https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

Run PowerShell command

setlocal enabledelayedexpansion
set "_Key=HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
for /f tokens^=3 %%i in ('%__APPDIR__%reg.exe query "!_Key!"^|find/i "Personal"')do call set "docs_folder=%%~i"
if exist %docs_folder% echo %docs_folder%

Query the registry

setlocal enabledelayedexpansion
set "_Key=HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
for /f tokens^=3 %%i in ('%__APPDIR__%reg.exe query "!_Key!"^|find/i "Personal"')do call set "docs_folder=%%~i"
if exist %docs_folder% echo %docs_folder%