Calling function from included batch file with a parameter

前端 未结 3 1194
庸人自扰
庸人自扰 2021-01-14 07:15

In my main batch file I include another batch file and want to call a function defined in there, code looks like following:

@echo off
call define_wait.bat

i         


        
相关标签:
3条回答
  • 2021-01-14 07:56

    Although there are several ways to call a function that reside in a separate library file, all methods require to change the way to call the library functions in the calling program, and/or insert additional code at beginning of the library file in order to identify the called function.

    There is an interesting trick that allows to avoid all these details, so both the main and the library files contain the original code, and just 2 lines needs to be added to the main file. The method consist in switch the context of the running main Batch file to the library file; after that, all functions in the library file are available to the running code. The way to do that is renaming the library file with the same name of the main file. After that, when a call :function command is executed, the :function label will be search in the library file! Of course, the files must be renamed back to the original names before the program ends. Ah! I almost forget the key point of this method: both the initial and final renames must be executed in a code block in the main file. A simple example:

    main.bat

    @echo off
    echo Calling :test and :hello functions in the library.bat file:
    
    rem Switch the context to the library file
    (ren "%~NX0" temp.bat  &  ren library.bat "%~NX0"
    
    call :test
    echo Back from library.bat :test function
    
    call :hello
    echo Back from library.bat :hello function
    
    rem Switch the context back to the main file
    ren "%~NX0" library.bat  &  ren temp.bat "%~NX0")
    
    echo Continue in main file
    

    library.bat

    :test
    echo I am :test function in library.bat file
    exit /B
    
    :hello
    echo I am :hello function in library.bat file
    exit /B
    

    A drawback of this method is that if a run-time error happens when the files are renamed, the files remains renamed, but this may be fixed in a very simple way. For example, a check.bat file may check if the library.bat file exists, and do the rename back if it was not found.

    0 讨论(0)
  • 2021-01-14 08:10

    I wasn't aware of this until jeb commented it, but here's a quick demonstration of the call bug he mentioned, using some utility functions I had lying around.

    functions.bat:

    :length <"string">
    rem // sets errorlevel to the string length (not including quotation marks)
    setlocal disabledelayedexpansion
    if "%~1"=="" (endlocal & exit /b 0) else set ret=1
    set "tmpstr=%~1"
    for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        setlocal enabledelayedexpansion
        if not "!tmpstr:~%%I,1!"=="" (
            for %%x in ("!tmpstr:~%%I!") do endlocal & (
                set /a ret += %%I
                set "tmpstr=%%~x"
            )
        ) else endlocal
    )
    endlocal & exit /b %ret%
    
    :password <return_var>
    rem // prompts user for password, masks input, and sets return_var to entered value
    setlocal disabledelayedexpansion
    <NUL set /P "=Password? "
    set "psCommand=powershell -noprofile "$p=read-host -AsSecureString;^
    $m=[Runtime.InteropServices.Marshal];$m::PtrToStringAuto($m::SecureStringToBSTR($p))""
    for /f "usebackq delims=" %%p in (`%psCommand%`) do endlocal & set "%~1=%%p"
    goto :EOF
    

    main.bat:

    @echo off & setlocal
    
    rem // demo return value
    call :password pass
    
    setlocal enabledelayedexpansion
    echo You entered !pass!
    
    rem // demo bubbling up of %ERRORLEVEL%
    call :length "!pass!"
    echo Password length is %ERRORLEVEL%
    
    endlocal
    goto :EOF
    
    rem // ====== FUNCTION DECLARATIONS =======
    
    :length <"string">
    :password <return_var>
    functions.bat %*
    

    Output:

    Password? *********
    You entered something
    Password length is 9

    This web page offers an explanation:

    If you execute a second batch file without using CALL you may run into some buggy behaviour: if both batch files contain a label with the same name and you have previously used CALL to jump to that label in the first script, you will find execution of the second script starts at the same label. Even if the second label does not exist this will still raise an error "cannot find the batch label". This bug can be avoided by always using CALL.

    If you've ever done any coding in C++, it helps to think of the labels in main.bat as function declarations in a .h file, while the labels in functions.bat would correspond to function definitions in a .cpp file. Or in .NET, the main.bat labels would be like DllImport("functions.bat") so to speak.

    0 讨论(0)
  • 2021-01-14 08:19

    Working function bat that forwards it's parameters to it's subfunction:

    @echo off
    call %*
    goto :EOF
    
    :WAIT_AND_PRINT
    set /a time=%1
    for /l %%x in (1, 1, %time%) do (
        ping -n 1 -w 1000 1.0.0.0 > null
        echo|set /p=.
    )
    goto :EOF
    
    :WAIT
    set /a time="%1 * 1000"
    ping -n 1 -w %time% 1.0.0.0 > null
    goto :EOF
    

    In the main bat I now don't include the batch file anymore but call it directly like following:

    call define_wait.bat :WAIT_AND_PRINT 5
    
    0 讨论(0)
提交回复
热议问题