DOS - Function
Collection
The functions listed in this
section serve as copy source to enhance your batch program. Simply copy paste the function into your
batch program and start calling them.
The provided test codes serve as examples on how to call the functions.
2 String Trimming Left
and Right - :trim, :trimLeft, :trimRight
4 Time Of Day and runtime
measurements - :getTod, :getHHMMSSDD, :Tod2Str, :TodDiffNow
5 Circulate thru a List -
:getNextInList
6 Choose from List of
last entered Values - :choiceListInput
7 Opening the Registry
Editor at a defined Location - :regedit
8 Float <-> Integer
Conversion - :F2I, :I2F
9 Extracting text blocks
from a File - :extractFromFile
10 Get THIS computers
IP address - :getIP
12 Progress Indicator -
:initProgress, :doProgress
1
Variable Persistency
- :setPersist, :getPersistentVars, :savePersistentVars,
:restorePersistentVars
|
|
|
Variable persistency can be
archived by storing the variable of interest into a file when the DOS batch
terminates and read them back in when the DOS batch starts up. The setPersist
function marks a variable to be persistent.
The savePersistentVars
function stores the persistent variables into a file. The restorePersistentVars
function reads the variables back in from a file. |
What
it's good for |
-
Remembering the
state of the batch program for the next run -
Allow user profiles -
Store information to
be used in the next run -
Implement execution
counters |
Code |
:setPersist -- to be called to initialize persistent variables :: -- %*: set command arguments set %* GOTO:EOF :getPersistentVars -- returns a comma separated list of persistent
variables :: -- %~1: reference to return
variable SETLOCAL set retlist= set parse=findstr /i
/c:"call:setPersist" "%~f0%"^|find /v
"ButNotThisLine" for /f "tokens=2 delims== "
%%a in ('"%parse%"') do (set retlist=!retlist!%%a,) ( ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" SET %~1=%retlist% ) GOTO:EOF :savePersistentVars -- Save values of persistent variables into a file :: -- %~1: file name SETLOCAL echo.>"%~1" call :getPersistentVars persvars for %%a in (%persvars%) do (echo.SET
%%a=!%%a!>>"%~1") GOTO:EOF :restorePersistentVars -- Restore the values of the persistent variables :: -- %~1: batch file name
to restore from if exist "%FilePersist%"
call "%FilePersist%" GOTO:EOF |
|
|
Test Code |
rem.--define the filename where
persistent variables get stored rem.
just add a + to the name of THIS file, i.e. "DosTips.bat" -
"DosTips+.bat" set FilePersist=%~dpn0+%~x0 rem.--initialize the persistent
variables call:setPersist var=Hello rem.--read the persistent variables
from the storage call:restorePersistentVars
"%FilePersist%" rem.--modify the persistent variable echo.var = '%var%' echo. echo.Enter new string for var then
run the batch again. set /p var=var = rem.--save the persistent variables
to the storage call:savePersistentVars
"%FilePersist%" |
|
|
Test Code Output |
var = 'Hello' Enter new string for var then run the
batch again. var = |
2
String Trimming Left
and Right - :trim, :trimLeft, :trimRight
|
|
|
Three functions to trim spaces
around a value, i.e. left, right, left and right. |
Code |
:trimLeft -- trim leading spaces : -- %~1: variable reference, string
to be trimmed for /f "tokens=* delims= "
%%a in ("!%~1!") do set %~1=%%a GOTO:EOF :trimRight -- trim trailing spaces : -- %~1: variable reference, string
to be trimmed SETLOCAL set s=!%~1! :trimRight_LOOP if "%s:~-1%"==" "
set s=%s:~0,-1%&goto:trimRight_LOOP (ENDLOCAL & REM.-- RETURN VALUES
IF "%~1" NEQ "" SET %~1=%s% ) GOTO:EOF :trim -- trim leading and trailing spaces :
-- %~1: variable reference, string to be trimmed call:trimLeft %~1 call:trimRight %~1 GOTO:EOF |
|
|
Test Code |
set s=left trim nothing& call:trimLeft
s&echo."!s!" set s= left trim one& call:trimLeft
s&echo."!s!" set s= left trim
plenty&call:trimLeft s&echo."!s!" set s=right trim nothing& call:trimRight
s&echo."!s!" set s=right trim one & call:trimRight
s&echo."!s!" set s=right trim plenty &call:trimRight
s&echo."!s!" set s=trim nothing& call:trim
s&echo."!s!" set s= trim one left and one right
& call:trim
s&echo."!s!" set s= trim plenty left and right &call:trim
s&echo."!s!" |
|
|
Test Code Output |
"left trim nothing" "left trim one" "left trim plenty" "right trim nothing" "right trim one" "right trim plenty" "trim nothing" "trim one left and one
right" "trim plenty left and
right" |
3
String Length -
:strLen
|
|
|
The :strLen function uses a
binary search approach to determine the length of a string. |
Code |
:strLen -- returns the length of a string via binary search, maximum
length 1023 :: -- %~1: in - varible name of a string
variable :: -- %~2: out- string length SETLOCAL set str=A!%~1!& rem keep the A up front to ensures we get
the length and not the upper bond rem it also avoids trouble in
case of empty string set len=0 set /a n=1024 set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n set /a n^>^>=1, len+=n if !str:~%len%!. == . set /a len-=n ( ENDLOCAL & REM RETURN VALUES
IF "%~2" NEQ "" SET %~2=%len% ) GOTO:EOF |
|
|
Test Code |
for /l %%a in (0,1,10) do (
set s=
for /l %%b in (0,1,%%a) do if /i %%b NEQ 0 set s=!s!x
call:strLen s len
echo."!s!" - length !len! ) |
|
|
Test Code Output |
"" - length 0 "x" - length 1 "xx" - length 2 "xxx" - length 3 "xxxx" - length 4 "xxxxx" - length 5 "xxxxxx" - length 6 "xxxxxxx" - length 7 "xxxxxxxx" - length 8 "xxxxxxxxx" - length 9 "xxxxxxxxxx" - length 10 |
4
Time Of Day and
runtime measurements - :getTod, :getHHMMSSDD, :Tod2Str, :TodDiffNow
|
|
|
The getTod function returns a Time Of Day (Tod) integer value with a
precision of 1/100th of a second.
Together with the other functions this can be used for time capture
calculations like runtime measurements. The getHHMMSSDD function allows
extracting the hours, minutes, seconds, and 1/100th of seconds
from a Tod integer. The Tod2Str function allows to
freely format a Tod integer into a string, i.e. put the seconds, hours,
minutes where you want them. |
What it's good for |
-
Runtime measurement |
Limits |
-
No corrector for
days where daylight saving time is being turned on or off |
Code |
:getTod -- get a Time of Day value in 1/100th seconds ::
-- %~1: out - timo of day SETLOCAL set /a t=0 for /f "tokens=1-4
delims=:." %%a in ("%time: =0%") do set /a
t=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100 ( ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" SET %~1=%t% ) GOTO:EOF :getHHMMSSDD -- split a Time Of Day integer into hours, minutes,
seconds, 1/100th :: -- %~1: in - time of day as integer :: -- %~2: out - hours :: -- %~3: out - minutes :: -- %~4: out - seconds :: -- %~5: out - 1/100th SETLOCAL set /a t=%~1 set /a hh=t/360000 set /a t-=hh*360000 set /a mm=t/6000 set /a t-=mm*6000 set /a ss=t/100 set /a t-=ss*100 ( ENDLOCAL & REM RETURN VALUES
IF "%~2" NEQ "" SET %~2=%hh%
IF "%~3" NEQ "" SET %~3=%mm%
IF "%~4" NEQ "" SET %~4=%ss%
IF "%~5" NEQ "" SET %~5=%t% ) GOTO:EOF :Tod2Str -- format a Time Of Day integer into a time string :: -- %~1: out - output string :: -- %~2: in - time of day :: -- %~3: in - formatter string, default is HH:MM:SS.DD SETLOCAL set tod=%~2 set f=%~3 if "%f%"=="" set
f=[TTTT]& rem --if no
format given assume [TTTT] format set
f=%f:[TTTT]=[H]:[MM]:[SS].[DD]%&
rem --replace [TTTT] with the default format call:getHHMMSSDD tod h m s
d& rem --extract the
numbers from the Time Of Day value rem -- ensure two digits, add leading
0 where necessarily set HH=0!h!&set HH=!HH:~-2! set MM=0!m!&set MM=!MM:~-2! set SS=0!s!&set SS=!SS:~-2! set DD=0!d!&set DD=!DD:~-2! rem -- replace the format specifyiers
with real values set f=!f:[HH]=%HH%! set f=!f:[MM]=%MM%! set f=!f:[SS]=%SS%! set f=!f:[DD]=%DD%! set f=!f:[H]=%h%! set f=!f:[M]=%m%! set f=!f:[S]=%s%! set f=!f:[D]=%d%! ( ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" (SET %~1=%f%) ELSE (ECHO.%f%) ) GOTO:EOF :TodDiffNow -- echos the time of day difference of Now-Base :: -- %~1: in - Base time as variable :: -- %~2: in - formatter string,
default is HH:MM:SS.DD :: -- %~3: out- diff time or empty for
screen output SETLOCAL set base=!%~1! call:getTod curr& rem --get the current
Time Of Day set /a diff=curr-base& rem --subtract the base to get the
difference if /i diff LSS 0
diff+=24*60*60*100& rem --when measuring over midnight add a full day call:Tod2Str s %diff%
"%~2"& rem
--format the difference as string ( ENDLOCAL & REM RETURN VALUES
IF "%~3" NEQ "" (SET %~3=%s%) ELSE (ECHO.%s%) ) GOTO:EOF |
|
|
Test
Code |
set delay=5 call:getTod
t echo.Starting
a %delay%s delay via ping... FOR /l %%a
in (%delay%,-1,1) do ping -n 2 -w 1 127.0.0.1>NUL echo....finished. call:TodDiffNow
t "The %delay%s delay via ping really took [TTTT]" |
|
|
Test
Code Output |
Starting a 5s delay via ping... ...finished. The 5s delay via ping really took
0:00:06.39 |
|
|
5
Circulate thru a
List - :getNextInList
|
|
|
The getNextInList function allows a variable to circulate thru a set
of values. Each time calling this
function the next entry in the choice list will be returned. After passing the last entry the function
will start again with the first entry. |
What it's good for |
-
Creating a state automat
in DOS -
Let the user
circulate through option rather than force typing. |
Code |
:getNextInList -- return next value in list :: -- %~1 - in/out ref to current
value, returns new value :: -- %~2 - in choice list, must start with delimiter
which must not be '@' SETLOCAL set lst=%~2& rem.-- get the choice list if "%lst:~0,1%" NEQ
"%lst:~-1%" echo.ERROR Choice list must start and end with the
delimiter&GOTO:EOF set dlm=%lst:~-1%& rem.-- extract the delimiter used set old=!%~1!& rem.-- get the current value set fst=&for /f
"delims=%dlm%" %%a in ("%lst%") do set
fst=%%a&rem.--get the first entry rem.-- replace the
current value with a @, append the first value set lll=!lst:%dlm%%old%%dlm%=%dlm%@%dlm%!%fst%%dlm% rem.-- get the
string after the @ for /f "tokens=2 delims=@"
%%a in ("%lll%") do set lll=%%a rem.-- extract the
next value for /f "delims=%dlm%" %%a
in ("%lll%") do set new=%%a ( ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" (SET %~1=%new%) ELSE (echo.%new%) ) GOTO:EOF |
|
|
Test Code |
rem.--modify the persistent variable set choiceList=,MO,TU,WE,TH,FR,SA,SU, echo.choice list =
"%choiceList%" set var= echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var = '%var%'&call:getNextInList
var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" echo.var =
'%var%'&call:getNextInList var "%choiceList%" |
|
|
Test Code Output |
choice list =
",MO,TU,WE,TH,FR,SA,SU," var = '' var = 'MO' var = 'TU' var = 'WE' var = 'TH' var = 'FR' var = 'SA' var = 'SU' var = 'MO' var = 'TU' |
Note |
If var starts out empty or with
a bogus value then the getNextInChoiceList function will assign the first
value in the choice list, which is nice default behavior. |
6
Choose from List of last entered Values -
:choiceListInput
|
|
|
The choiceListInput function lets the user enter a value. The value entered is returned by the
function and added to the end of a choice list. The choice list is shown next time this
function is being called, and thus allows the user to pick from the list of
last entered value. The last chosen or
newly entered value is added to the end of the choice list and acts as
default input next time this function is being called. The choice list is being stored
into a variable. The name of this
variable is to be passed into the function, which allows this function to be
called using different choice lists. |
What it's good for |
-
Increases user
efficiency -
Allows picking
number from list instead of having to enter a long strings -
Only need to pick a
value when different from last run, otherwise just hit enter |
Tip |
Make the choice list variable
persistent in order to have it available over multiple batch file executions. |
Code |
:choiceListInput - lets the user choose from list of last entered values : -- %~1 - out, returns input
value : -- %~2 - in/out, ref to
choice list, returns trimmed reordered choice list : -- %~3 - in, list title : -- %~4 - in, list entry count
limit SETLOCAL ENABLEDELAYEDEXPANSION set l=,!%~2!,& rem.-- get the choice list set t=%~3& rem.-- get the list title set c=%~4& rem.-- get the list entry count
limit set m=& rem.-- a message set l2=, set v= :choiceListInput_LOOP1 echo.%t% set i=0&for %%a in (%l%) do ( set
/a i+=1
set l2=!l2!!i!;%%~a,
set v=%%~a
echo. !i! - %%~a ) if "%m%" NEQ ""
echo. ^>^> %m% echo.
Make a choice or enter a new value [%v%] set v1=%v% set /p v1= : echo. set v2=!v1!&set
v2=!v2:,=!&set v2=!v2:@=!&set v2=!v2:;=!&set v2=!v2:"=! rem.--reject entry with illegal
character if "!v1!" NEQ
"!v2!" (
set m=Note: ,;@" and empty string not allowed. Try again.
goto:choiceListInput_LOOP1 ) rem.--if first character is minus
then remove the entry set remove=&if "%v1:~0,1%"=="-"
set remove=y&set v1=%v1:~1% set v=%v1% rem.--if number chosen then find
corresponding value set l3=!l2:,%v%;=,@! if "%l3%" NEQ
"%l2%" (
for /f "delims=@ tokens=2" %%a in ("!l3!") do set
l3=%%a
for /f "delims=,"
%%a in ("!l3!") do set v=%%a ) rem.--remove value from list if exist set l3=%l% set l=!l:,%v%,=,! if
"%remove%"=="y" (
if "%l%"=="%l3%" (set m='%v%' cannot be removed
from list
) ELSE (set m='%v%' has been removed from list)
goto:choiceListInput_LOOP1 ) if "%l%"=="%l3%"
echo. ^>^>'%v%' has been added
to the list rem.--add to the value to the end set l=!l:~1!%v% rem.--enforce the list entry count
limit if requested if "%c%" NEQ "" (
set i=0&for %%a in (%l%) do set /a i+=1
if /i !i! GTR !c! ( for /f "delims=,
tokens=1,*" %%a in ("!l!") do ( set l=%%b echo. ^>^>'%%a' dropped out of the list )
) ) ( ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" (SET %~1=%v%) ELSE (echo.%v%)
IF "%~2" NEQ "" (SET %~2=%l%) ELSE (echo.%l%) ) goto :eof |
|
|
Test Code |
if "%~1"=="" (
set z=%~dpn0.tmp
if exist "!z!"
echo.a>>"!z!"
echo.b>>"!z!"
echo.c>>"!z!"
echo.d>>"!z!"
echo.>>"!z!"
echo.2>>"!z!"
echo.-d>>"!z!"
echo.-1>>"!z!"
echo.-1>>"!z!"
echo.z>>"!z!"
"%~f0" auto<"!z!" ) rem.--modify the persistent variable set choiceList= set var= call:choiceListInput var choiceList
"Selection List:" 3&echo.
--'!var!' has been selected call:choiceListInput var choiceList
"Selection List:" 3&echo.
--'!var!' has been selected call:choiceListInput var choiceList
"Selection List:" 3&echo.
--'!var!' has been selected call:choiceListInput var choiceList
"Selection List:" 3&echo.
--'!var!' has been selected call:choiceListInput var choiceList
"Selection List:" 3&echo.
--'!var!' has been selected call:choiceListInput var choiceList
"Selection List:" 3&echo.
--'!var!' has been selected call:choiceListInput var choiceList
"Selection List:" 3&echo.
--'!var!' has been selected |
Test Code Output |
Selection List:
Make a choice or enter a new value []
:
>>'a' has been added to the list
--'a' has been selected Selection List:
1 - a
Make a choice or enter a new value [a]
:
>>'b' has been added to the list
--'b' has been selected Selection List:
1 - a
2 - b
Make a choice or enter a new value [b]
:
>>'c' has been added to the list
--'c' has been selected Selection List:
1 - a
2 - b
3 - c
Make a choice or enter a new value [c]
:
>>'d' has been added to the list
>>'a' dropped out of the list
--'d' has been selected Selection List:
1 - b
2 - c
3 - d
Make a choice or enter a new value [d]
:
--'d' has been selected Selection List:
1 - b
2 - c
3 - d
Make a choice or enter a new value [d]
:
--'c' has been selected Selection List:
1 - b
2 - d
3 - c
Make a choice or enter a new value [c]
: Selection List:
1 - b
2 - c
>> 'd' has been removed from list
Make a choice or enter a new value [c]
: Selection List:
1 - c
>> 'b' has been removed from list
Make a choice or enter a new value [c]
: Selection List:
1 - c
>> 'b' cannot be removed from list
Make a choice or enter a new value [c]
:
>>'z' has been added to the list
--'z' has been selected |
|
|
7
Opening the Registry
Editor at a defined Location - :regedit
|
|
|
When opening the registry editor
regedit.exe it will have the last
registry key remembered and opens right where the user left off the last time
running it. The last registry key is
being remembered in the registry itself using the LastKey value in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit. To have regedit.exe open up at a specific location we just have to set
the LastKey value properly before
invoking the regedit.exe. The regedit function |
What is it good for |
-
Increasing user
efficiency -
Shortcut for
frequently observed registry entries |
Code |
:regedit - opens the regedit at a
defined location : -- %~1 - location SETLOCAL set
StartKey=%~1 set
tmpfile=%Temp%\RegeditLastKey.reg&
rem --use a temporary .reg file to be imported via regedit set
StartKey=%StartKey:\=\\%&
rem --double up the back slashes echo.Windows
Registry Editor Version 5.00>"%tmpfile%" echo.[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit]>>"%tmpfile%" echo."LastKey"="%StartKey%">>"%tmpfile%" regedit /s
"%tmpfile%"&
rem --import the temporary .reg file start /b
regedit&
rem --launch the registry editor and continue GOTO:EOF |
|
|
Test Code |
REM --this
example WILL open the registry editor at HKEY_CURRENT_USER\Software\Microsoft call:regedit
"HKEY_CURRENT_USER\Software\Microsoft" |
8
Float <->
Integer Conversion - :F2I, :I2F
|
|
|
DOS does not support floating
point arithmetic. However with a
little trick floating point arithmetic is still possible. A string storing a floating point value can
be converted into an integer using the F2I
function. To preserve precision the
float will be multiplied by 10, 100, 1000, or more so that the fractions move
into the integer part of the value.
Having an integer now the value can be used in calculation using
standard DOS commands. At the end the
integer can be converted back into a float using the I2F function. This
works perfect for additions and subtractions. The
result of a multiplication of two factors will need to be divided by the
correcting factor 10, 100, 1000, or whatever was used. In
a division it is necessarily to multiply the dividend first the correcting
factor 10, 100, 1000, or whatever was used. |
Code |
:F2I --
float to integer : -- %~1: var ref, for in
place conversion : -- %~2: precision SETLOCAL set f=!%~1! set /a prec=%~2 + 1&rem.--keep
one more for rounding set nnn=&for /l %%n in
(1,1,%prec%) do set nnn=!nnn!0 set mul=1%nnn% for /f "tokens=1,2 delims=.
" %%a in ("%f%") do (set f1=%%a&set f2=%%b%nnn%) set f2=1!f2:~0,%prec%!&rem.--HexCludge--need
the 1 up front to not be confused with hex set /a i=f1*mul+f2 set /a i+=5&rem.--ensure correct
rounding set /a
i-=mul&rem.--HexCludge--need to subtract the 1 added earlier set i=%i:~0,-1% (ENDLOCAL & REM.-- RETURN VALUES
IF "%~1" NEQ "" SET %~1=%i% ) GOTO:EOF :I2F --
integer to float : -- %~1: var ref, for in
place conversion : -- %~2: precision SETLOCAL set i=!%~1! set prec=%~2 set nnn=&for /l %%n in
(1,1,%prec%) do set nnn=!nnn!0 set mul=1%nnn% set /a f1=i/mul set /a f2=i%%mul set f2=%nnn%%f2% set f2=!f2:~-%prec%! set f=%f1%.%f2% (ENDLOCAL & REM.-- RETURN VALUES
IF "%~1" NEQ "" SET %~1=%f% ) GOTO:EOF |
|
|
Test Code |
echo.Example conversion Float to
Integer set x=3.03 call:F2I x 3&echo.%x% F2I
!x! set x=1.1 call:F2I x 3&echo.%x% F2I
!x! set x=1.1114 call:F2I x 3&echo.%x% F2I
!x! set x=1.1115 call:F2I x 3&echo.%x% F2I
!x! set x=9.9994 call:F2I x 3&echo.%x% F2I
!x! set x=9.9995 call:F2I x 3&echo.%x% F2I
!x! echo. echo.Example conversion Integer to
Float set y=1 call:I2F y 3&echo.%y% I2F
!y! set y=12 call:I2F y 3&echo.%y% I2F
!y! set y=123 call:I2F y 3&echo.%y% I2F
!y! set y=1000 call:I2F y 3&echo.%y% I2F
!y! set y=1234 call:I2F y 3&echo.%y% I2F
!y! set y=12345 call:I2F y 3&echo.%y% I2F
!y! echo. set /p x=Input x= set /p y=Input y= call:F2I x 3 call:F2I y 3 set calc=x*y & set /a
z=!calc!/1000 & call:I2F z 3 & echo.!calc!= !z! set calc=x/y & set /a z=1000*!calc!
& call:I2F z 3 & echo.!calc!= !z! set calc=x+y & set /a
z=!calc! & call:I2F z 3 &
echo.!calc!= !z! set calc=x-y & set /a
z=!calc! & call:I2F z 3 &
echo.!calc!= !z! |
|
|
Test Code Output |
Example conversion Float to Integer 3.03 F2I
3030 1.1 F2I
1100 1.1114 F2I
1111 1.1115 F2I
1112 9.9994 F2I
9999 9.9995 F2I
10000 Example conversion Integer to Float 1 I2F
0.001 12 I2F
0.012 123 I2F
0.123 1000 I2F
1.000 1234 I2F
1.234 12345 I2F
12.345 Input x=12.12 Input y=3.03 x*y = 36.723 x/y = 4.000 x+y = 15.150 x-y = 9.090 |
9
Extracting text
blocks from a File - :extractFromFile
|
|
|
The
extractFromFile function allows extracting blocks of lines from a file
the extracted block will be send to the output window or can optionally be
piped into a file. Each block is identified by a
begin marker and an optional end marker.
If the end marker is omitted then the extraction stops at the end of
the file. If
begin marker can be any string that is unique with in the file. If the begin marker end with a $ sign then
all variables used in the block are being substituted by its values. |
What
it's good for |
-
Compact DOS batch,
easy distribution -
Embedding text
blocks within the batch file itself to be extracted at runtime -
I.e. Embed a FTP
script or a registry script within the DOS batch file |
Code |
:extractFromFile - extract lines from a file between begin and end mark :: - %~1: begin mark, use '...$'
mark to allow variable substitution :: - %~2: optional end mark,
default is end of file :: - %~3: optional source file,
default is THIS file SETLOCAL set bmk=%~1 set emk=%~2 set src=%~3 set /a b=-1 set /a e=-1 if "%src%"==""
set src=%~f0& ::- if no
source file then assume THIS file for /f "tokens=1,*
delims=:" %%a in ('"findstr /n /b /c:"%bmk%"
"%~f0""') do (
set b=%%a
set bmk=%%b ) if
/i %b%==-1 echo.ERROR: begin
mark '%bmk%' not found in '%src%'&GOTO:EOF if "%emk%"==""
(set /a e=2000000000) ELSE (
for /f "delims=:" %%a in ('"findstr /n /b
/c:"%emk%" "%~f0""') do ( if /i %b% LSS %%a if /i !e!==-1 set
e=%%a& rem -- find only the first one
after b
) ) if /i %e%==-1 echo.ERROR: end mark '%emk%' missing in
'%src%'&GOTO:EOF if /i %b% GEQ %e% echo.ERROR: end
mark '%emk%' detected before begin mark '%bmk%' in '%src%'&GOTO:EOF for /f "delims=:
tokens=1,*" %%a in ('"findstr /v /n /b /c:"#$*ReturnAll*$#"
"%src%""') do (
if /i %b% LSS %%a if /i %%a LSS %e% ( if
"%bmk:~-1%"=="$" ( rem --substitution variables
within %%b call echo.%%b ) ELSE ( rem --no variable substitution echo.%%b )
) ) GOTO:EOF |
|
|
Test Code |
@ECHO OFF REM.-- Prepare the Command Processor SETLOCAL ENABLEEXTENSIONS SETLOCAL ENABLEDELAYEDEXPANSION echo.Extracting hello world block
into "HelloWorld.bat" file call:extractFromFile
"###Hello" "###">"HelloWorld.bat" set var=This variable will been
substituted :) echo. echo.Extracting a block to screen
with variable substitution call:extractFromFile
"###SubstBlock" "###" echo. echo.Extracting a block to screen
as-is call:extractFromFile "###AsIsBlock" :skip REM.-- End of application FOR /l %%a in (5,-1,1) do (TITLE
%title% -- closing in %%as&ping -n 2 -w 1 127.0.0.1>NUL) TITLE Press any key to close the
application&ECHO.&GOTO:EOF ::------------------------------------------------------------------ ::-- functions start below here ::------------------------------------------------------------------ :extractFromFile - extract lines from a file between begin and end mark :: - %~1: begin mark, use '...$' mark to
allow variable substitution :: - %~2: optional end mark,
default is end of file :: - %~3: optional source file,
default is THIS file SETLOCAL set bmk=%~1 set emk=%~2 set src=%~3 set /a b=-1 set /a e=-1 if "%src%"==""
set src=%~f0& ::- if no
source file then assume THIS file for /f "tokens=1,*
delims=:" %%a in ('"findstr /n /b /c:"%bmk%"
"%~f0""') do (
set b=%%a
set bmk=%%b ) if
/i %b%==-1 echo.ERROR: begin
mark '%bmk%' not found in '%src%'&GOTO:EOF if "%emk%"==""
(set /a e=2000000000) ELSE (
for /f "delims=:" %%a in ('"findstr /n /b
/c:"%emk%" "%~f0""') do ( if /i %b% LSS %%a if /i !e!==-1 set
e=%%a& rem -- find only the first
one after b
) ) if /i %e%==-1 echo.ERROR: end mark '%emk%' missing in
'%src%'&GOTO:EOF if /i %b% GEQ %e% echo.ERROR: end
mark '%emk%' detected before begin mark '%bmk%' in '%src%'&GOTO:EOF for /f "delims=:
tokens=1,*" %%a in ('"findstr /v /n /b
/c:"#$*ReturnAll*$#" "%src%""') do (
if /i %b% LSS %%a if /i %%a LSS %e% ( if
"%bmk:~-1%"=="$" ( rem --sustitution variables
within %%b call echo.%%b ) ELSE ( rem --no variable substitution echo.%%b )
) ) GOTO:EOF ::------------------------------------------------------------------ ::-- blocks start below here ::------------------------------------------------------------------ ###Hello### @ECHO OFF ECHO.Hello world ECHO. PAUSE GOTO.EOF ### ###SubstBlock###$ Arg 0 = %~0 batch = %~d0 batch = %~nx0 mark
= %bmk% var
= %var% ### ###AsIsBlock### Arg 0 = %~0 batch = %~d0 batch = %~nx0 mark
= %bmk% var
= %var% |
|
|
Test Code Output |
Extracting hello world block into
"HelloWorld.bat" file Extracting a block to screen with
variable substitution Arg 0 = :extractFromFile batch = C: batch = myExtract.cmd mark
= ###SubstBlock###$ var
= This variable will been substituted :) Extracting a block to screen as-is Arg 0 = %~0 batch = %~d0 batch = %~nx0 mark
= %bmk% var
= %var% |
10 Get THIS computers IP address - :getIP
|
|
|
The
getIP function filters the IP
address from the ipconfig command
output and returns it to the caller. |
Code |
:getIP -- return THIS computers IP
address ::
-- %~1 - out, IP SETLOCAL set ip= for /f "tokens=2,* delims=:.
" %%a in ('"ipconfig|find "IP Address""') do set
ip=%%b ( ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" (SET %~1=%ip%) ELSE (echo.%ip%) ) goto :eof |
|
|
Test Code |
rem.show this computers IP address call:getIP ip echo This computers IP is: %ip% |
|
|
Test Code Output |
This computers IP is: 4.239.36.199 |
11 Wait, Sleep, Hold - :sleep
|
|
|
The
:sleep function puts the batch execution
on hold for a certain amount of second. |
Code |
:sleep -- waits some seconds before returning ::
-- %~1 - in, number of seconds to wait FOR /l %%a in (%~1,-1,1) do (ping -n
2 -w 1 127.0.0.1>NUL) goto :eof |
12 Progress Indicator - :initProgress, :doProgress
|
|
|
When a function processes tasks
in multiple steps it's always nice to give the user some progress
indication. The initProgress function will initialize a progress counter by
telling it the number of steps to come and initializes the progress display
to 0%. Calling doProgress after
finishing each step will update the progress display by the internally
calculated percentage. I.e. Let's say
20 steps are to be performed then each call to doProgress will update the progress display by 5 percent. The progress will be shown in
the Window title which as two advantages.
First, the progress output will not clutter the output window. Second, even a minimized window will still
show the progress in the Windows task bar. |
What
it's good for |
-
Show progress when
copying multiple files. Call initProgress passing the number of files to be
copied. Call doProgress after each
file. -
Show progress when
executing loops, Call initProgress
passing the loop count. Insert the doProgress call as last command
within the loop. |
Code |
:initProgress -- initialize an internal progress counter and display
the progress in percent :: -- %~1: in - progress counter maximum, equal to 100
percent :: -- %~2: in - title string formatter, default is '[P]
completed.' set /a ProgressCnt=-1 set /a ProgressMax=%~1 set ProgressFormat=%~2 if
"%ProgressFormat%"=="" set ProgressFormat=[PPPP] set
ProgressFormat=!ProgressFormat:[PPPP]=[P] completed.! call :doProgress GOTO:EOF :doProgress -- display the next progress tick set /a ProgressCnt+=1 SETLOCAL set /a
per=100*ProgressCnt/ProgressMax set per=!per!%% title %ProgressFormat:[P]=!per!% GOTO:EOF |
|
|
Test Code |
@ECHO OFF REM.-- Prepare the Command Processor SETLOCAL ENABLEEXTENSIONS SETLOCAL ENABLEDELAYEDEXPANSION REM.-- Set the window title SET title=Window Title TITLE %title% set maxcnt=11 call:initProgress maxcnt
"%title%: [P]
progress"& rem --format
string is optional echo.Simulating an task with !maxcnt!
cycles... for /l %%C in (1,1,!maxcnt!) do (
echo.%%C&call:sleep 1
call:doProgress ) |
Test Code Output |
Window Title: 0% progress Window Title: 9% progress Window Title: 18% progress Window Title: 27% progress Window Title: 36% progress Window Title: 45% progress Window Title: 54% progress Window Title: 63% progress Window Title: 72% progress Window Title: 81% progress Window Title: 90% progress Window Title: 100% progress |