A batch file takes arguments from its command line and moves between its own lines with labels.
It reuses the same two ideas to make subroutines. This page follows Microsoft’s
call and
goto
pages.
Arguments
| Reference | Value |
|---|---|
%0 | The name the batch file was run by, as typed (with a path and extension only if they were typed). Inside a call :label subroutine it is reported to be the label |
%1 … %9 | The first nine arguments. An argument that is missing is an empty string |
%* | All the arguments after %0, as typed, spaces and quotes kept. shift does not change it (reported). The %~ modifiers cannot be used on it |
Arguments are separated by spaces, tabs, and also by ,, ; and =
(reported: build.bat a=b gives %1 as a and %2 as
b). Text in double quotes is one argument, and the quotes stay in the value. Only nine
arguments can be named directly: use shift or %* for more.
Since an empty argument makes if %1==x a syntax error, the usual tests are
if "%~1"=="" and, in old scripts, if [%1]==[].
Modifiers
A ~ after the percent sign expands the argument and then changes it. Modifiers are not
case sensitive and can be combined in any order, and the argument number ends the syntax
(Microsoft’s call page). The same modifiers apply to for variables.
| Form | Expands to |
|---|---|
%~1 | The argument with surrounding quotes removed |
%~f1 | A fully qualified path name |
%~d1 | A drive letter only |
%~p1 | A path only |
%~n1 | A file name only |
%~x1 | A file extension only |
%~s1 | The path with short (8.3) names only |
%~a1 | The file attributes |
%~t1 | The date and time of the file |
%~z1 | The size of the file |
%~$PATH:1 | The fully qualified name of the first match found in the directories of the PATH variable (or any other variable name), or an empty string if not found |
Combined: %~dp1 (drive and path), %~nx1 (file name and extension),
%~fs1 (full path, short names), %~dp$PATH:1 (drive and path of the match in
PATH), %~ftza1 (a line like dir shows). The most used form is
%~dp0, the folder the batch file is in, ending with a backslash, which makes a script
independent of the current directory: "%~dp0tools\run.exe".
shift
shift moves each argument down one place: %2 becomes %1 and so
on, and the tenth argument becomes %9. %0 is not changed. With command
extensions, shift /n starts shifting at the nth argument (0 to 9) and leaves the
ones before it. A loop that takes each argument in turn:
:next
if "%~1"=="" goto done
echo Argument: %~1
shift
goto next
:done
shift.goto
goto label continues at the line after the label :label. It searches the
file from the start, so a label above the goto works too.
- The match is not case sensitive, and the name is the text up to the first space; the characters
;and=cannot be in it (Microsoft). - With command extensions on,
goto :eofgoes to the end of the current batch file, or of the currentcall :labelsubroutine, with no label needed. The colon is required, andgoto:eofis accepted. - If the label is not found, the batch file stops with
Label not found. - A
gotoout of the middle of a( )block or aforloop is allowed and abandons the block. - The label can be built from a variable:
goto answer%errorlevel%jumps to:answer0,:answer1(Microsoft’sifexample).
call
Without call, running another batch file from a batch file hands control over and does
not come back. call runs it and returns to the next line when it ends (Microsoft).
| Form | Effect |
|---|---|
call file [arguments] | Run a batch file (the name must have a .bat or .cmd extension, says Microsoft; call also runs programs and built-in commands, and expands the line a second time) |
call :label [arguments] | Run the lines from the label as a subroutine, in a new context with its own %0–%9, until the end of the file, goto :eof or exit /b. Control then returns after the call. Needs command extensions. The first time the end of the file is reached after a jump to a label, control returns; the second time the file ends |
call command | Run the command after a second round of percent expansion: call echo %%var%% shows the value of the variable whose name is in var. Carets are also doubled in this pass |
- Do not use pipes or redirection with
call, says Microsoft. calldoes nothing at the prompt outside a script.- A batch file may call itself, but needs an exit condition or it loops until the stack is exhausted.
- The called file shares the environment of the caller. Variable changes stay unless the callee used
setlocal. A subroutine has no local variables of its own beyond that. - The exit code of the callee is available in
%errorlevel%afterwards.
Subroutines
A subroutine is a label with exit /b or goto :eof at its end, called with
call :name args, and kept after the main code so that execution does not fall into it. A
result is returned in the exit code or in a variable whose name the caller passes in.
@echo off
call :square 7 result
echo 7 squared is %result%
call :banner "Done"
exit /b 0
:square
set /a %2=%1*%1
goto :eof
:banner
setlocal
set "text=%~1"
echo ==== %text% ====
endlocal
exit /b 0
exit /b [code] ends the current batch file or subroutine and sets
ERRORLEVEL to code; exit without /b ends the whole
cmd.exe (Errorlevel and exit codes).
Running other programs
- A program runs and the batch file waits for it, if it is a console program. A Windows (GUI) program is started and the batch file goes on;
start /waitwaits for it. start "" "C:\Program Files\App\app.exe"– the first quoted argument ofstartis a window title, so an empty title is put in front of a quoted path.cmd /c file.batruns a batch file in a newcmd.exe, whose variable changes are lost on return.
Not described
Unknown
- Reference:
%0inside a subroutine, the behaviour of%*undershift,,;=as argument separators and the second-pass caret doubling ofcallare from reported analysis and the interpreter’s own help, not from Microsoft’s pages, and were not run oncmd.exefor this page.