Dienstag, 27. November 2007

BATCH_ Subroutines in Windows Batch

Since Windows 2000 you can use subroutines (depending on the understanding and definition of "function" and "procedure", one can also refer to them as "procedures", that can manipulate both local and global variables and don't return any value ("void")).

Basically, a subroutine is a number of commands between a label and a GOTO:EOF statement.
:MY_SUBROUTINE
ECHO Called MY_SUBROUTINE and ending now...
GOTO:EOF

GOTO:EOF is often written without a space, as it is used as a special GOTO command: It jumps to the End of File, thus ending the currently executed script.

That is the reason why a subroutine is not called with GOTO :MY_SUBROUTINE, but with
CALL :MY_SUBROUTINE

This executes the current batch AGAIN in the current context, but jumps immediately to the given label. And that is the reason why ending the script at the end of the subroutine - it just ends the execution started through the CALL command.

A subroutine has its own parameters, you don't have access to the "parent" batch parameters unless they were stored in an environment variable.
CALL :MY_SUBROUTINE "param 1" "param 2"
GOTO:EOF

:MY_SUBROUTINE
ECHO The first parameter is %~1.
ECHO The second parameter is %~2.
GOTO:EOF

You can see that there is another GOTO:EOF after the CALL command. You don't want your first subroutine being executed after your script finished, do you? This is the basic structure of a batch script using subroutines:
@ECHO off
REM Documentation here
REM Version 1.0 of 2007/11/11

... preprocessing, setting variables etc ...
... script body ....

GOTO:EOF
REM ############################
REM SUBROUTINES
:MY_SUBROUTINE
... subroutine body
GOTO:EOF


What about the local context I mentioned at the beginning? That does not differ from standard batch scripts:
:MY_SUBROUTINE
SETLOCAL
... local context here ...
ENDLOCAL
GOTO:EOF


As subroutines do not provide a way of returning any value (and, of course, there is no direct way to store the result of an execution in a variable), here is what I do. By convention, I reserve the global variable %RESULT% for storing the result of the last called subroutine that should return a value. You can think of it like putting a value onto a one-element stack.
:MY_SUBROUTINE
SET RESULT=4711
GOTO:EOF

This won't work if using local context within the subroutine, however due to the cmd.exe-nature there is way to preserve a variable after ending the local context:
:MY_SUBROUTINE
SETLOCAL
SET RESULT=4711
ENDLOCAL & SET RESULT=%RESULT%
GOTO:EOF

A little explanation: As the batch reads a full line, expands all variables, parses the line and then finally executes all contained commands in order, the important line looks like this after expansion:
ENDLOCAL & SET RESULT=4711
See, variable preserved and available in global context. Sometimes you want to preserve more than one variable, so you add additional SET statements. But be careful and do not insert a space before the ampersand - that space will contained in your variable!
ENDLOCAL & SET A=%A%& SET B=%B%& SET C=%C%

A little advise at the end: document your subroutines, otherwise you won't know what parameters it takes, what global variables it manipulates or requires or what value it "returns". I use double colons for subroutine documentation.
:: Shortens a string to the given number of characters.
:: PARAMS
:: 1 string to shorten
:: 2 number of characters
:: RESULT String shortened string
:SHSTR
SETLOCAL ENABLEDELAYEDEXPANSION
SET TEMP=%~1
ENDLOCAL & SET RESULT=!TEMP:~0,%~2!
GOTO:EOF

See also this article about handling parameters and variables containing special characters.
Jeremy (Gast) - 6. Mai, 16:49

You taught me something!

I've been using internal calls for several years now (call :MySub), but I never knew you could call external subroutines (call Lib.cmd :MySub)

That wasn't even the reason I found your site. I was looking for a way to remove non-printable characters. I found your :GET_ASCII_CHARS sub, which I think will work perfectly!

Awesome site! Keep it up!

Jeremy (Gast) - 6. Mai, 17:19

Update

Ahhh, I see now how the external subs work. Slick move!

Looking closer, the GET_ASCII_CHARS won't do what I thought it would, but I think I can still munge something together with some of the other subs to get rid of non-printable characters.

Still loving the site. I'll be checking it out in more detail from home.
Rich (Gast) - 15. Dez, 16:30

Parametes

You can handle parameters in a much simpler way. Your subroutine does not need to know the name of the global variable. You can pass it as one of the variables.

Example script, tested under Windows XP.

@echo off
:: Test if the current user is a local adminisrator.

:: Assume the users is not an administrator.
SET ISADMIN=FALSE

::Test current user.
call :ADMINTEST %USERNAME% ISADMIN

echo %ISADMIN%

pause
Goto END
::------------------------------------------------------------------------------
:: This routine will test if the User ID passed in parameter1 is a member
:: of the local administrators group. It will return "TRUE" in parameter 2
:: if the User ID is an admin.
:ADMINTEST
SETLOCAL
net localgroup administrators | find "%1%"
if %ERRORLEVEL% EQU 0 (
ENDLOCAL & SET "%~2=TRUE"
)
GOTO:EOF
::------------------------------------------------------------------------------
:END

Wyndham Hotel Near Me

Hi there superb website! Does running a blog such as this take a lot of work? I have virtually no knowledge of programming however I was hoping to start my own blog in the near future. Anyway, should you have any ideas or tips for new blog owners please share. I understand this is off subject but I simply had to ask. Thanks!

jaguars apparel (Gast) - 8. Dez, 10:29

Im happy I now registered

Greetings, I do think your web site could possibly be having web browser compatibility problems. When I take a look at your web site in Safari, it looks fine however, if opening in I.E., it has some overlapping issues. I simply wanted to provide you with a quick heads up! Other than that, wonderful site!

Just want to say Hello!

Can you tell us more about this? I'd love to find out more details.

Reflog

Informationstechnische Howtos, Hinweise und Merkwürdiges

Batchlib v1.0 2008-03-29

Aktuelle Beiträge

HOWTO_ O2 DSL Surf &...
Der O2 DSL Surf & Phone-Router ist für die...
cypressor - 12. Feb, 19:57
Uptweak Windows XP Home...
There are a lot of annoying limitations in Windows...
cypressor - 9. Okt, 19:30
BATCHLIB_ Batchlib package...
Download Batchlib package v1.0 (5 KB zip file) What...
cypressor - 29. Mrz, 19:10
BATCHLIB_ Batchlib library...
The batchlib library string.cmd is part of the batchlib...
cypressor - 29. Mrz, 18:10

Homepage Ticker

Links

Status

Online seit 4140 Tagen
Zuletzt aktualisiert: 28. Jun, 11:32
RSS XML 1.0 Button-Get-Firefox

batch
batchlib
howto
tech
video
Profil
Abmelden
Weblog abonnieren