【问题标题】:Is there any way to maintain a batch script library?有什么方法可以维护批处理脚本库吗?
【发布时间】:2013-11-18 13:15:40
【问题描述】:

我正在编写一个复杂的批处理补丁文件并生成其他文件。我知道这批不是最好的,但我大部分时间都在工作。但是,如果我不想为每个子例程创建一个单独的文件,那么在所有文件中保留所有子例程重复是一件令人头疼的事情。我的问题是是否有任何方法可以保留多个子程序的库文件并以某种方式调用它们?

【问题讨论】:

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


    【解决方案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
    

    一些cmets:

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

    其他想法:

    • 我对批处理脚本比较陌生,所以并非一切都是完美的。
    • 这是在大约 1 小时内完成的,我敢肯定它缺少一些东西!
    • 在构造参数数组(即引号)时是否应该进行一些转义?

    非常感谢任何其他 cmets!

    【讨论】:

      【解决方案2】:

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

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

      例如:

      (
      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?

      【讨论】:

      • 是的,但这仍然是一个技巧。有两行要输入的事实,它们出错的机会增加了风险并使调试变得困难。我的库方法只是一种将所有函数保存在一个文件中的方法,人们可能不喜欢这种方法。我可以看到将所有函数保存在单独的文件中的好处(C++ 与 Java 方法)。但我喜欢你的把戏!我认为有很多地方可以应用它,我一定会记住它:D
      猜你喜欢
      • 2012-02-14
      • 1970-01-01
      • 2017-10-14
      • 2015-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-10
      • 1970-01-01
      相关资源
      最近更新 更多