Yes, there is a possibility: use start
to let the script restart itself, provide the label of the sub-routine as an argument and use goto
rather than call
to continue execution at that point:
@echo off
if not "%~1"=="" goto %~1
:MAIN
setlocal
echo Here I am in the MAIN thread
start "" /B cmd /D /C "%~f0" :ASYNC
echo Here I am in the MAIN thread again
endlocal
exit /b 0
:ASYNC
setlocal
echo Now I am in the ASYNC thread
timeout /T 10
endlocal
exit /b 0
When you run the script and want to first execute the main section, you must not provide an argument. If you do, it will be interpreted as a jump label. To avoid that, you could check whether the (first) argument begins with a :
and skip the goto
if not. Replace the line if not "%~1"=="" goto %~1
by the following to achieve that:
set "ARG1=%~1" & if not defined ARG1 shift /1 & goto :MAIN
if "%ARG1:~,1%"==":" goto %ARG1%
This is not absolutely safe against any odd arguments (like "&"&
), but it will serve well in most situations. However, regard that the argument positions may not be as expected, because of the additional label argument (check out the argument string %*
, which is even not going to be affected by shift
).
Note, that the sub-routine then becomes executed in a new cmd.exe
instance, so any environment changes will not reach the main instance.
There is even a better way to accomplish what you want, without affecting any potential arguments, namely to embed the label of the sub-routine in the script path itself when restarting the script (technique courtesy of user jeb, see his answer to How to pipe the final result of a windows batch for loop into another command):
@echo off
for /F "tokens=3 delims=:" %%Z in ("%~0") do goto :%%Z
:MAIN
setlocal
echo Here I am in the MAIN thread
start "" /B cmd /D /C "%~d0\:ASYNC:\..%~pnx0" %*
echo Here I am in the MAIN thread again
endlocal
exit /b 0
:ASYNC
setlocal
echo Now I am in the ASYNC thread
timeout /T 10
endlocal
exit /b 0
The key portion is the augmented path string %~d0\:ASYNC:\..%~pnx0
, which is going to be resolved to %~d0%~pnx0
(that is the full script path %~0
).
The sub-routine becomes again executed in a new cmd.exe
instance.