有没有办法维护批处理脚本库?

时间:2013-11-18 13:15:40

标签: batch-file label shared-libraries goto subroutine

我正在编写一个包含其他文件生成的复杂批量补丁文件。我知道批次不是最好的,但我大部分时间都在使用它。但是,如果我不想为每个子例程创建单独的文件,那么很难将所有子例程保留在所有文件中。我的问题是,是否有任何方法可以保存多个子程序的库文件并以某种方式调用它们?

2 个答案:

答案 0 :(得分:1)

所以我要回答我自己的问题,因为我设法让事情有效。

假设您有main.bat和lib.bat文件。

Main.bat

@ECHO off
SETLOCAL
    SET return=
    SET reference=this is just a reference variable

    CALL lib.bat return "subroutine" "static arg" reference
    IF NOT "%ERRORLEVEL%"=="0" (
        ECHO Execution failed - %ERRORLEVEL%
        EXIT /b 1
    )

    ECHO.
    ECHO subroutine return value: "%return%"
    ECHO.

    CALL lib.bat NUL "procedure" "static arg" reference

    ECHO.

    CALL lib.bat return "error" "static arg" reference
    IF NOT "%ERRORLEVEL%"=="0" (
        ECHO Execution failed - %ERRORLEVEL%
        EXIT /b 1
    )
ENDLOCAL
EXIT /b 0

Lib.bat

@ECHO off

::
:: ===================================================================================
:: Library Main Handler
:: ===================================================================================
:: %~1  - [out] - NUL | reference to a return variable
:: %~2  - [in]  - subroutine label to be invoked
:: %~3+ - [in]  - optional arguments to the subroutine
::
:: ERRORLEVEL is passed through to the caller
::

SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
    SET callSub=%~2
    SET return=
    SET args=

    IF "%callSub%"=="" (
        ECHO Subroutine label was not provided to the library. 1>&2
        EXIT /b 1
    )

    :buildUpArgumentList
    IF "%~3"=="" GOTO end_buildUpArgumentList
       SET args=%args% "%~3"
    SHIFT /3
    GOTO buildUpArgumentList
    :end_buildUpArgumentList

    IF NOT "%~1"=="NUL" (
        call:%callSub% return %args%
        IF NOT "!ERRORLEVEL!"=="0" (
            EXIT /b !ERRORLEVEL!
        )
    ) ELSE (
        call:%callSub% %args%
        IF NOT "!ERRORLEVEL!"=="0" (
            EXIT /b !ERRORLEVEL!
        )
    )
(
    ENDLOCAL
    IF NOT "%~1"=="NUL" (
        SET %~1=%return%
    )
)
EXIT /b 0

::
:: ===================================================================================
:: Library Subroutine Definitions
:: ===================================================================================
::

:subroutine <r_return> <static> <r_reference>
    SETLOCAL
        ECHO subroutine^<static^>: "%~2"
        ECHO subroutine^<r_reference^>: "!%~3!"
    (
        ENDLOCAL
        SET %~1=subroutine executed OK
    )
EXIT /b 0

:procedure <static> <r_reference>
    SETLOCAL
        ECHO procedure^<static^>: "%~1"
        ECHO procedure^<r_reference^>: "!%~2!"
    ENDLOCAL
EXIT /b 0

:error <r_return> <static> <r_reference>
    SETLOCAL
        ECHO error^<static^>: "%~2"
        EXIT /b 2
        ECHO error^<r_reference^>: "!%~3!"
    (
        ENDLOCAL
        SET %~1=error executed OK
    )
EXIT /b 0

输出:

subroutine<static>: "static arg"
subroutine<r_reference>: "this is just a reference variable"

subroutine return value: "subroutine executed OK"

procedure<static>: "static arg"
procedure<r_reference>: "this is just a reference variable"

error<static>: "static arg"
Execution failed - 2

一些意见:

  • 库子例程调用类似于常规函数签名:()但没有括号。
  • 您会注意到库代码检查是否传递了NUL。如果是这种情况,则返回值既不会传递给子例程也不会返回。
  • 子程序参数支持n个参数。
  • 该库支持错误级别传递。
  • 如果库中不存在提供的子例程标签,批处理将返回ERRORLEVEL = 1并显示消息“系统找不到指定的批处理标签 - [标签]。”

其他想法:

  • 我对批处理脚本相对较新,所以并非一切都很完美。
  • 这是在1小时内完成的,我确信它遗漏了一些东西!
  • 构造参数数组时应该执行一些转义(即引号)吗?

非常感谢任何其他评论!

答案 1 :(得分:1)

更简单的方法是使用以下技巧:

  1. 在括号中包含调用库函数的代码。
  2. 在括号开头,将当前批处理文件重命名为其他名称,并将库文件重命名为当前批处理文件。
  3. 现在您可以像以前一样调用任何库函数。
  4. 括号结束前,请将文件重命名为原始名称。
  5. 例如:

    (
    rem Switch the active context to the library file:
    ren "%~0" main.bat
    ren libraryFile.bat "%~0"
    rem From this line on you may call any function in the library file, for example:
    call :FUNCTION
    
    rem Switch the context back to original file
    ren "%~0" libraryFile.bat
    ren main.bat "%~0"
    )
    

    有关详细信息,请参阅: How to package all my functions in a batch file as a seperate file?