Skip to content

Functions

rbaltrusch edited this page Feb 14, 2021 · 3 revisions

Functions and Scripts

Definition

A function in batch can be defined in a batch script by setting a label and then calling it using call, as below:

@echo off
goto :main

:my_function
echo this is inside the function
exit /b

:main
call :my_function

A function can be terminated either with exit /b or goto :eof, although exit /b should be preferred, as an error code may be specified when exiting, e.g.:

::everything went fine
exit /b 0

Local scope

So far, the function defined in the example above used the same scope as the global scope of the script. The command setlocal may be used inside functions to mark the start of a local scope, which can be terminated with endlocal, as below:

:my_function
setlocal
    ::this variable is only available in the local scope
    set my_var=test
    echo %my_var%
endlocal

::the content of the local variable cannot be accessed anymore
echo %my_var%

exit /b

Return value

To pass out a value from the local scope to global scope, we need to chain the endlocal statement using the & operator, as we have access to both the global and local scope on that line. An example to clarify this quirky behaviour:

:my_function
setlocal
    set inner=test
endlocal & set outer=%inner%
echo %outer%
exit /b

Delayed variable expansion

Finally, some constructs such as the for loop often require delayed variable expansion (wrapping a variable in ! signs). This is the same as the regular variable expansion using % signs, with the only difference being that both expansion types can be nested, and that the for loop only re-evaluates a value modified in it if delayed variable expansion is used. To clarify the for loop behaviour, here is one example in which we loop five times and increase the variable counter by 1 each time:

set /a counter=0
for /l %%c in (1 1 5) do set /a counter=%counter%+1
echo %counter%

In the example above, one might expect the variable counter to equal to 5 once the loop is done, but the actual value would be 1, as the variable was only expanded to the value of its initial assignment (0), and was not updated again in the for loop.

Instead, we get the intended result (5) by using delayed expansion, as below:

setlocal enabledelayedexpansion
for /l %%c in (1 1 5) do set /a counter=!counter!+1
echo %counter%
endlocal

Input arguments

Any number of input arguments to a function can be freely passed after calling the label. In the example below, we pass in three input arguments to the function my_function: test, "some string", and 1:

call :my_function test "some string" 1

The input arguments inside the function may be accessed using special variables in the format %~1. %~0 contains the name of the batch file currently executing, %~1 contains the first argument, %2 the second, and so on. %* is a list of all input arguments, which can be looped over using a for-loop. In the example below, we call the function my_function by passing one input argument hello and echoing it out inside the function:

@echo off
goto :main

:my_function
echo first argument passed is %~1
exit /b

:main
call :my_function hello

Note that an arbitrary number of argument variables may be used in the function, but this does not require the caller to pass those arguments. If, for example, we access the second input argument in the function using %~2, but the caller only passed one input argument, then the %~2 variable, in normal batch fashion will appear as being empty.

Scripts

Functions and scripts in batch behave much the same way, with similar syntax for calling them, passing in input arguments, and accessing any input arguments. The only difference is that instead of calling a label using the :label syntax, we call the script using its name directly, such as:

call my_batfile "some input argument"
Clone this wiki locally