Windows Batch
Windows batch scripting
TOC
- Arguments
- Variables
- Date and Time
- Loops
- String operations
- Echo into the same line
- ESC sequences
- Run PowerShell command
- Query the registry
Links
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]!
)
- Each element of the array needs to be specifically defined using the set command.
- The array element name is enclosed on
!....! - The ‘for’ loop with the /L parameter for moving through ranges is used to iterate through the array
keerah: not sure about this statement, look at the first example in #Arguments, it works fine)
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
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
-
FOR /D %variable IN (set) DO command [command-parameters]
If set contains wildcards, then specifies to match against directory names instead of file names. -
FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
Walks the directory tree rooted at[_drive:_]_path_, executing theFORstatement in each directory of the tree.
If no directory specification is specified after/Rthen the current directory is assumed.
If set is just a single period (.) character then it will just enumerate the directory tree. -
FOR /L %variable IN (start,step,end) DO command [command-parameters]
The set is a sequence of numbers from_start_to_end_, by_step_amount.
So(1,1,5)would generate the sequence1 2 3 4 5and(5,-1,1)would generate the sequence5 4 3 2 1.
NOTE! If_step_equals 0, and_end_is greater than_start_, then the loop will continue forever -
FOR /F ["options"] %variable IN (filenameset) DO command [command-parameters]
FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
or, withusebackq(Windows 2000 or later):
FOR /F ["usebackq options"] %variable IN (filenameset) DO command [command-parameters]
FOR /F ["usebackq options"] %variable IN ("string") DO command [command-parameters]
FOR /F ["usebackq options"] %variable IN ('command') DO command [command-parameters]
Note!
Keep in mind that in aFORloop, 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%