How do I call anotherfile.bat :label correctly in Batch?

Viewed 67

I have a Batch file that's a library of functions like

:findmsbuild
if exist msbuildpath.txt (
    for /f %%i in (msbuildpath.txt) do set MSBUILD="%%i\MSBuild.exe"
) else (
    set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
    for /f "delims=" %%i in ('!VSWHERE! -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe') do set MSBUILD="%%i"
)
exit /b

And the official documentation for call says that I should be able to call directly to a label in another file like

call library.bat :findmsbuild

but what happens instead is, the interpreter executes library.bat from the first line. What am I doing wrong? The calling Batch file is approximately

setlocal enableextensions enabledelayedexpansion
cd "%~dp0"
call library.bat :findmsbuild
echo %MSBUILD%
2 Answers

What are you doing wrong? Trusting Microsoft's documentation.

You can either call externalbatch or call :internalroutine.

To do what you want, you'd need to put a line like goto %1 at the start of your library file - and remember then that the parameter list has the label at the start, so you'd need to shift it, and %* would retain the label as the first parameter.

Preface: job / function is used interchangeably below.

It is possible to call functions in this way, however you need to script it into your library.bat program. That means assessing provided arguments, determining if they correspond to a valid job, and determining the action to take such as calling a job with %* arguments or providing help output.

Note: using Call %* to execute a label supplied as %1 when calling library.bat will:

  • desirable behaviour:
    • Allow arguments provided to a called job to reside in their intended positions as :jobname becomes %0 when called.
  • Potentially undesirable behaviours:
    • Result in the doubling of any carets present in the arguments. If relevent to any jobs, you'll need to account for that in the relevant job.
    • Expand any %variables% present in the argument string supplied to library.bat (defined or undefined)

An example of executing the desired functionality:

@Echo off

    Echo(

    Set "ExitCode=0"
    2> nul (
        Rem // search this file for labels matching Argument 1 at line beginning.
        %SystemRoot%\System32\Findstr.exe /BLI "%~1" "%~f0" > nul && (
            Call %* || (
                Call Set "ExitCode=%%Errorlevel%%"
                (Call )
            )
        ) || (
            Echo("%~1"|%SystemRoot%\System32\Findstr.exe /R "[:][.]*" && (
                Rem // No labels matching Argument 1 at line beginning. Argument 1 begins with a ":"
                Echo(Invalid job. Valid jobs:
                For /f "tokens=1" %%J in ('%SystemRoot%\System32\Findstr.exe /R "^[:][.]*" "%~f0"')Do Echo(%%J
                Exit /b 1
            ) || If not "%~1" == "" (
                Rem // Argument 1 does not begin with a ":"
                Echo(No job call attempt. Args: %*
                Echo(
                Echo(To call a job:
                Echo(Call "%~f0" :jobname %%*
            )
        )
    )

Exit /b %ExitCode%

:demo
    Echo(Jobname %0 JobArgs: [%*]
Exit /b 0

:job
    Echo(Jobname %0 JobArgs: [%*]
    REM // demostrate return of errorlevel in ExitCode variable facilitate && || logic
    set /A ExitCode=%random% %% 2
Exit /b %ExitCode%
Related