GOTO in a Windows batch script is generally safe to use, and sometimes necessary. But there are three non-intuitive design features that are worth noting:
1) Do not GOTO a label placed within a parenthesized block of code
You can GOTO a label placed within a parenthesized block, but it will probably not give you the result you intend. For example, a GOTO within a FOR loop DO block will immediately terminate the loop. If the GOTO references a label within the DO block, control is transferred correctly to the label location, but the batch parser now knows nothing about the FOR loop context. The code will be executed as if it is not within a loop. See the accepted answer to (Windows batch) Goto within if block behaves very strangely for more information.
2) Location of the label can affect performance.
This is generally not an issue unless you are dealing with a really large script.
When performing a GOTO :label
(or CALL :label
), the batch processor begins scanning from the current script location, looking for the first occurrence of :label
. If it reaches the end of the file without finding the label, then it loops back to the top and continues the search. An error will be raised if it reaches the starting point without finding the label. So performance can sometimes be improved in very large scripts by structuring the script such that labels appear shortly after their respective GOTO (or CALL). Of course, if a label is referenced from many locations, that may be impossible.
3) The same label can actually be safely used in multiple locations (not advised)
Once you understand the label scan process described in point 2 above, you can safely reuse a label if you are careful.
For example, the following script will work properly:
@echo off
for %%A in (1 2 3 X Y Z) do (
echo %%A
if %%A equ 3 goto break
)
:break
for %%A in (A B C 8 9 10) do (
echo %%A
if %%A equ C goto break
)
:break
-- OUTPUT --
1
2
3
A
B
C
Although reuse of labels works, it is not a good practice since it could confuse anyone else that tries to interpret or debug the script.