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.
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
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.
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:
What about the local context I mentioned at the beginning? That does not differ from standard batch scripts:
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.
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:
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:
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.
See also this article about handling parameters and variables containing special characters.
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
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
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
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
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
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
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
:: 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.
cypressor - 27. Nov, 13:04
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
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
http://hotelsnearme.club/ (Gast) - 29. Sep, 19:36
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!
http://www.ilco.hr/ (Gast) - 25. Apr, 21:39
Just want to say Hello!
Can you tell us more about this? I'd love to find out more details.
You taught me something!
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!
Update
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.