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:

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