How to call dynamic label in another .bat file

If I want to call: foo to foo.bat from bar.bat, I:

::foo.bat
echo.wont be executed
exit /b 1
:foo
echo foo from foo.bat
exit /b 0

      

and

::bar.bat
call :foo
exit /b %errorlevel%
:foo
foo.bat
echo.will also not be executed

      

But if I don't know the name of the label, but pass it as a parameter, I am stuck

::bar.bat
:: calling a dynamic label is no problem
call :%~1
exit /b %errorlevel%
::don't know how to "catch-all" or set context of "current-label"
:%~1
foo.bat

      

+3


source to share


4 answers


Labels are searched by the parser literally before environment variables or argument references are resolved, so you cannot use them in methods.
However, I want to provide an approach that allows dynamic labels, although I don't understand what the purpose of this is, so this is more of a kind of academic answer ...

The file parser cmd

does not cache the batch file, it reads and executes it line by line or speaks correctly, it reads and executes each command line / block separately. Therefore, we can use this and let the batch file modify itself during its execution, given that the changed part is outside the currently executable part of the code. The following script does the following:



@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Check whether a label name has been delivered:
if "%~1"=="" (
    echo ERROR: No label name specified! 1>&2
    exit /B 1
)

rem /* Call sub-routine to replace the literal label string `:%~1`
rem    within this batch file by the given dynamic label name: */
call :REPLACE_LINE "%~f0" ":%%%%~1" ":%~1" || (
    rem /* In case the given label is `:REPLACE_TEXT`, display error
    rem    message, clean up temporary file and quit script: */
    >&2 echo ERROR: Label ":%~1" is already defined!
    2> nul del "%~f0.tmp"
    exit /B 1
)

rem // Perform call of the sub-routine with the dynamic label name:
call :%~1

rem /* Call sub-routine to replace the given dynamic label name
rem    within this batch file by the literal label string `:%~1`: */
call :REPLACE_LINE "%~f0" ":%~1" ":%%%%~1"

endlocal
exit /B


:REPLACE_LINE  val_file_path  val_line_LOLD  val_line_LNEW
    ::This sub-routine searches a file for a certain line
    ::case-insensitively and replaces it by another line.
    ::ARGUMENTS:
    ::  val_file_path   path to the file;
    ::  val_line_LOLD   line to search for;
    ::  val_line_LNEW   line to replace the found line;
    setlocal DisableDelayedExpansion
    rem // Store provided arguments:
    set "FILE=%~1" & rem // (path of the file to replace lines)
    set "LOLD=%~2" & rem // (line string to search for)
    set "LNEW=%~3" & rem // (line string to replace the found line)
    set "LLOC=%~0" & rem // (label of this sub-routine)
    rem // Write output to temporary file:
    > "%FILE%.tmp" (
        rem /* Read the file line by line; precede each line by a
        rem    line number and `:`, so empty lines do not appear as
        rem    empty to `for /F`, as this would ignore them: */
        for /F "delims=" %%L in ('findstr /N "^" "%FILE%"') do (
            rem // Store current line with the line number prefix:
            set "LINE=%%L"
            setlocal EnableDelayedExpansion
            rem // Check current line against search string:
            if /I "!LINE:*:=!"=="!LOLD!" (
                rem // Current line equals search string, so replace:
                echo(!LNEW!
            ) else if /I not "!LNEW!"=="!LLOC!" (
                rem // Current line is different, so keep it:
                echo(!LINE:*:=!
            ) else (
                rem /* Current line equals label of this sub-routine,
                rem    so terminate this and return with error: */
                exit /B 1
            )
            endlocal
        )
    )
    rem /* Searching and replacement finished, so move temporary file
    rem    onto original one, thus overwriting it: */
    > nul move /Y "%FILE%.tmp" "%FILE%"
    endlocal
    exit /B


:%~1
    ::This is the sub-routine with the dynamic label.
    ::Note that it must be placed after all the other code!
    echo Sub-routine.
    exit /B

      

Basically, it first replaces the literal string (string) :%~1

with the string provided as the first command line argument, then calls that section, call :%~1

and finally restores the original literal label string. The replacement is controlled by a subroutine :REPLACE_LINE

.

+1


source


You can use a park parser trick.
You don't need to do anything foo.bat

for this to work.

::foo.bat
echo.wont be executed
exit /b 1
:func1
echo foo from foo.bat
exit /b 0

:unknown
echo Hello from %0 Func :unknown
exit /b

      

You only need to add labels to bar.bat

which you want to call infoo.bat



@echo off
::bar.bat
call :unknown
echo Back from Foo
call :func1
echo Back from Foo
exit /b %errorlevel%

:unknown
:func1
foo.bat
echo NEVER COMES BACK HERE

      

The trick is that after calling the label in bar.bat

and then running foo.bat without , calling it (only foo.bat

) loads the foo.bat file and the last named shortcut jumped.

+1


source


foo.bat (secondary):

@echo off
echo   this is foo.bat
REM check, if the label is defined in this script:
findstr /xi "%~1" %~f0 >nul 2>&1 || goto :error
goto %~1

:foo
echo     reached foo.bat, label :foo
exit /b 0

:error
echo       wrong or missing label: "%~1"
exit /b 1

      

bar.bat (main)

@echo off
echo this is bar.bat
call foo.bat :foo
echo back to bar.bat - %errorlevel%
call foo.bat :foe
echo back to bar.bat - %errorlevel%
call foo.bat
echo back to bar.bat - %errorlevel%
exit /b

      

0


source


Since aschipfl is already stated correctly, you cannot have a dynamic label, but you can call existing labels dynamically, but you must check for existence before calling it like Stephan but in the primary batch.
So it's a combination of Stephans and jebs.

:: bar.bat
@echo off
REM check, if the label is defined in this script:
If "%~1" neq "" findstr /xi "%~1" %~f0 >nul 2>&1||goto :error&&Call :%~1
call :Func1
echo Back from Foo
call :func2
echo Back from Foo
exit /b %errorlevel%

:error
echo       wrong or missing label: "%~1"
exit /b 1

:func1
:func2
foo.bat
echo NEVER COMES BACK HERE

      


:: foo.bat 
@Goto :Eof

:func1
echo     reached foo.bat, label :func1
exit /b 0

:func2
echo     reached foo.bat, label :func2
exit /b 0

      

Output example:

> bar
    reached foo.bat, label :func1
Back from Foo
    reached foo.bat, label :func2
Back from Foo

> bar fx
      wrong or missing label: "fx"

      

0


source







All Articles