Batch
New we will talk about another scripting language "Batch"
we will explain Batch in three Questions (what - how - when)
What is Batch Scripting ?
Batch is a language that allow us to do either repeated or complex task in much easier way (ex if you need to loop on specific directory and copy specific files to specific locations or you need to rename them)
batch script file is end with .cmd or .bat
batch is as any other programming langauge that has syntaxes and some limitations.
How we use it?
now we will talk about the language syntax and how we can use it.
first of all these are some common concepts about batch that you need to know before we start learning its syntax.
batch commands or options is not case sensitive only variables name is case sensitive
any line start with @ will hide command prompt and we do this at once in the beginning of the script through @ECHO OFF
this option /? used to open help page for most of commands.
Redirection Operators
Command > FileName "Redirect command output to a file."
Command >> FileName "Append command output into a file."
Command < FileName "Pass the text to command."
CommandA | CommandB "Redirect first command standard output to second command standard input."
stdin 0
stdout 1
stderror 2
dir c:\ 2> list.txt :: redirect STD out
dir C:\ > list.txt :: redirect STD error
dir C:\ > list.txt 2>&1 redirect STD out and STD error
dir C:\ > NUL
TYPE CON > lists.txt :: redirect STD in
Batch scripting syntax:
Comments:
to ways to add comments (the command rem or ::) then write what you want the will not executed.
Declaring variables:
this will be done through SET command.
set command has 3 ways of usage:
without any arguments: here will print all environment variables.
with variable name only without value: here will print the specific value for this variable.
with variable and value: here will create or rename that variable.
by default and without any option the value will be stored as a normal string
if we need to assign a numerical value we need to give /a option,
for example,
SET /a var1=expression => here we assign numerical values so we can perform arithmetic or logical operations on it.
But here
SET var1=20 => it will be treated as normal string so we can perform all string operations on it.
the last option that we can use with SET command /p : used when you need to set the variables from user input and the value of this variable will be determined during runtime.
String Manipulations:
%PATH:str1=str1% replace any occurrence of str1 to str2 in PATH variable
%PATH:~a,b% return characters from index "a" tell index "b-1"
%PATH:~-10% return the last 10 characters
Variables scope:
now after we learned about how we can create a variable and set and modify it we will talk about variables scope.
Local scope:
Local Scope (LS)
the lifetime and access scope is bounded by SETLOCAL and ENDLOCAL
Global Scope (GS)
can be accessed through any location in your script.
Before start to write script this ECHO command we need to use through all of incoming scripts
ECHO [ON | OFF].
here ECHO if we pass on, as option the command line will be printed each time, we execute any command.
if ECHO OFF the command line will be disappeared during execution and the result only will be printed of any command se we will be use it a lot to keep our terminal is clear
we will not forget the normal use of echo command that used to print message.
$ECHO "Your message here"
So back to LS and GS:
@echo off
set var1=STRING1
setlocal
set var2=STRING2
echo.
echo local scope variables values
echo.
echo var1 is %var1% and var is %var2%
endlocal
echo global scope variables values
echo.
echo var1 is %var1% and var is %var2%
exit 0
and this is the output.
how to send inputs to batch script?
we can do this as following provide that our test script file is Batch.bat
so, we will send them as following but with delimiter will be a space or comma.
Method 1: >>Batch.bat param1 param2 param3...
Method 2: >>Batch.bat Param1,Param2,Param3...
inside your script you can access them by its index that you pathed them to the CMD (index 0 is reserved for batch script name itself) we will start from index 1 [%1 for Param1] and so on.
working with numeric variables:
here we can apply arithmetic and logical operators on these expressions.
example:
set /a sum=%var1% + %var2%
echo sum of %a% and %b% is = %sum%
Conditions (Decision making)
we have IF and ELSE-IF
the syntax as following:
Hint: if else is introduced then Grouping () is required.
IF (Condition) Do Something
IF (Condition) (Do something) ELSE (Do something)
IF (Condition) (IF (Condition) (Do something))::nested if
Special IFs:
IF (NOT) defined VariableName (Do something)
IF (NOT) Exist FileName (Do something)
IF (Condition) GoTo :label
Relational Operators:
EQU, NEQ, LSS, LEQ, GTR, GEQ.
Example:
@echo off
set /a var1=100
set /a var2=100
IF %var1% equ %var2% (
echo both var1 and var2 are equal ) else (
echo both var1 and var2 are not equal
)
endlocal
exit 0
the output:
Loops:
loops mean do something that repeated under certain condition.
batch script only support for loops so ( while and Do-while) are not supported but can be implemented using goto and if condition.
FOR loop is a big command and the syntax is more complex so this allows FOR to do deferent options depend on the options that you will provide to it
these are all ways for using FOR loops (this screen shot is from help).
syntax: for %%variable in iterators do do_something
as a classical for loops consists of 3 parts:
(variable declaration, List, body).
iterators:
may be list (1 2 3 4).
or
may be range (start, increment, end).
ex
for %%a in (D:\documents\*) do @echo %%a::looping over files.
for /D %%y in (D:\documents\*) do @echo %%y::looping over directories.
for /D %%y in ("%dir%*") do (for %%a in ("%%y\*") do @echo %%a)
/d: will loop over all directories and subdirectories in the given directory.
/FL: will loop over a given list (Start , increment , end )
Hint here we can loop ascending or descending depending on the sign of increment.
/F: for file contents and file names
I advise you to read the help about FOR loop command as it will provide to you a lot of info that you need.
Now we will take some examples on for loop with different use cases.
@echo off
FOR /l %%i IN (0,1,10) DO ECHO %%i
FOR /l %%u IN (10,-1,0) DO ECHO %%u
endlocal
exit 0
then this is the output:
Read file content
you can see in figure below.
we loop on file content but there is a problem so we need to provide more options as we will see later.
@echo off
setlocal
FOR /f %%i IN (file1.txt,file2.txt,file3.txt) DO ECHO %%i
endlocal
exit 0
Working with files
Creating files:
echo "Hello">C:\new-file.txt
Reading from files:
FOR /F "tokens=* delims=" %%x in (new-file.txt) DO echo %%x
appending to files:
echo "This is the directory listing of C:\ Drive">C:\new.txt'
deleting files:
del test.bat
del c:\?est.tmp :: deltete any file end with est.tmp
moving files:
move c:\windows\temp\*.* c:\temp
move new.txt, test.txt c:\example
renaming files:
rename *.txt *.bak
so to solve the previous issu we that the reading of each line is ended at the first space so this is because the default delimiter is space or tap.
so we will modify the script to read all line so the delimiter will be a newline.
@echo off
setlocal
FOR /f "delims=\n" %%i IN (file1.txt,file2.txt,file3.txt) DO ECHO %%i
endlocal
exit 0
Nested loops:
FOR %%G ..... DO (FOR %%U .... DO ......)
now we will move to a new concept it is arrays:
we can say that batch scripting is not supporting arrays, but we simulate that we have array of a specific data type, and we can loop on elements through for loop.
SET /a arr[0]=10
before we access any array element we need to check if it is defined or not so we can check as following
IFDEFINED arr[12] (you can access it ).
functions:
batch implement functions as the same concept of other programming language but with different syntax.
the main benefits of using functions as it is in any other programming language reduce the program size plus readability and maintainability.
Functions syntax:
:label
<function body>
(GOTO: EOF or EXIT /B 0) ::we will return to caller through.
Functions with arguments:
:: calling a function with arguments.
call: Fun_Name arg1 arg2 ... ::these arguments may be used as inputs or outputs.
:Fun_Name
setlocal
set Local_var =Old_value
echo the first parameter is %~1 the second parameter is %~2
set %~1 = Set_argument1 ::here we return a global variable
endlocal & set %~1 = new_Value
goto EOF
look at the next example the we pass a two variable to the sum function.
@echo off
setlocal enabledelayedexpansion
set /a Sum=0
set /a First_Num=10
set /a Second_Num=20
echo Sum var before calling Sum_Fun is %Sum%
call :Sum_Fun First_Num Second_Num Sum
echo Sum var after calling Sum_Fun is %Sum%
:Sum_Fun
setlocal
set /a Sum_Loc=0
set /a Sum_Loc=!%~1!+!%~2!
(endlocal & set /a %~3 =%Sum_Loc%)
goto:EOF & rem return to caller
exit 0 :: exit form batch with error code 0
but we can improve this function and make it robust againest errors but chacking on the variables before accessing them .
(endlocal & IF "%~3" NEQ "" set /a %~3 =%Sum_Loc%)
now we can do a project on all we learnt together.
now we need to print all files that located in specific directory and subdirectories using arrays and functions.
@echo off
SETLOCAL EnableDelayedExpansion
set /a Dirs_Index=1
Set /a Current_Index=0
:: prompt user to enter this value so this make it more usefull
set /p ARR_DIR[%Current_Index%]=
:: this task is devided into 3 main blocks
:: first block read all subdirectories in a given directory
:LoopAllDirectories
call:GetAllSubDirectories !ARR_DIR[%Current_Index%]! Dirs_Index
IF %Current_Index% LSS %Dirs_Index% ( set /a Current_Index=%Current_Index%+1
GOTO:LoopAllDirectories) ELSE (
set /a Current_Index=0
GOTO:LoopOverAllDirectoriesFiles )
GOTO:EOF
:: here this function will fill array with new directories of subdirectories
:GetAllSubDirectories
FOR /D %%i IN (%~1) do (
if %%i NEQ "" (
set ARR_DIR[!%~2!]=%%i\*
set /a %~2=!%~2!+1 ) )
EXIT /B 0
:: here we will use the array ARR_DIR that contain all subdirectories located in a given directory
:LoopOverAllDirectoriesFiles
IF %Current_Index% LEQ %Dirs_Index% (
FOR %%g IN (!ARR_DIR[%Current_Index%]!) do (
echo %%g )
set /a Current_Index=Current_Index+1
GOTO:LoopOverAllDirectoriesFiles )
GOTO:EOF
endlocal
exit 0 & rem Exit script with return error code 0