从另一个批处理文件中批量调用子例程

时间:2015-05-11 12:48:18

标签: batch-file

file1.bat:

@echo off
 :Test
echo in file one
call file2.bat (Here i want to call only Demo routine in the file2.bat)

file2.bat:

:hello
echo in hello
:Demo
 echo in Demo

从批处理文件1中我想调用批处理文件2中的子程序 我尝试过例如call file2.bat:Demo,但它没有给出正确的结果。

我怎么能做到这一点?

4 个答案:

答案 0 :(得分:4)

子程序的文件必须如下所示:

@echo off
call :%*
exit /b %errorlevel%

:hello
echo in hello
exit /b 0
:Demo
 echo in Demo with argument %1
 exit /b 0

然后从另一个文件中你可以称之为

call file2.bat demo "arg-one"

答案 1 :(得分:4)

您可以将函数文件(在此示例中为library.cmd)编写为

@echo off
    setlocal enableextensions
    rem Not to be directly called
    exit /b 9009

:test
    echo test [%*]
    goto :eof

:test2
    echo test2 [%*]
    goto :eof

:testErrorlevel
    echo testErrorlevel
    exit /b 1

然后调用者批处理可以是

@echo off
    setlocal enableextensions disabledelayedexpansion

    call :test arg1 arg2 arg3
    call :test2 arg4 arg5 arg6
    call :testErrorlevel && echo no errorlevel || echo errorlevel raised

    goto :eof

:test
:test2
    echo calling function %0
    library.cmd %*

:testErrorlevel
    echo calling function %0
    library.cmd 

在这种情况下,需要在两个文件中使用相同的名称定义标签。

直接调用"库"批处理文件将替换call :label的上下文,并且在调用调用的批处理时,内部执行goto :label并且代码在指示的标签内继续。当被调用的批处理文件结束时,将释放上下文并继续call :label之后的代码。

<强>编辑

正如杰布在评论中指出的那样,这种方法存在缺陷。在被调用批处理文件中运行的代码不能使用%0来检索被调用函数的名称,它将返回批处理文件的名称。但是如果需要,调用者可以执行它,如示例代码所示。

编辑2016/12/27

回答dbenham,我无法知道这是编码错误还是预期的功能,但这是过程的工作原理

批处理&#34;上下文&#34>批处理文件中的行在内部BatLoop函数内处理。被建造。该函数作为其参数之一接收指向导致&#34; context&#34;的命令的指针。要被创造。

在此函数中,迭代批处理文件中的命令。循环遍历命令的循环在每次迭代中进行测试:如果启用了扩展,则它是批处理文件中的第一行,并且启动上下文的命令的参数以冒号(标签)开头,{{生成1}}以跳转到标签。

到目前为止,我必须假设这是处理goto语法的预期行为:创建一个新的&#34; context&#34;,加载文件,跳转到标签。

但是收到的命令参数永远不会改变,另一个变量用于跟踪批处理文件中命令的执行。如果将新批处理文件加载到/覆盖当前批处理&#34; context&#34; (我们没有使用call :label命令),在加载新批处理代码后,call重置行数(我们从加载文件的第一行开始),瞧,开始时的条件循环(已启用扩展,第一行,冒号)再次为真(指向的输入命令尚未更改)并生成新的BatLoop

答案 2 :(得分:0)

要多评论一下,这是我阅读答案得到的代码。它基本上为您提供了一个“实用程序”文件,您可以在其中将sub / fnc添加到公共库中进行代码维护。

A)例如,这是'utility_sub.cmd'文件:

REM ==============================================
REM             CALL THE SELECTED SUB
REM ==============================================
REM echo %~1
GOTO :%~1


REM ==============================================
REM               ERROR MANAGEMENT
REM ==============================================
    REM Ref : https://ss64.com/nt/exit.html
:RAISE_ERROR
    EXIT /B 1

:RESET_ERROR
    EXIT /B 0

    REM Demo call
    REM =========
    REM CALL :RAISE_ERROR
    REM echo RAISE_ERROR ERRORLEVEL = %ERRORLEVEL%

    REM If %ERRORLEVEL% GTR 0 (
        REM set msg="%tab%- Error detected ..."
        REM CALL :SUB_STDOUT_MSG !msg!, 1
    REM )

    REM CALL :RESET_ERROR
    REM echo RESET_ERROR ERRORLEVEL = %ERRORLEVEL%


REM ==============================================
REM                SUB_STDOUT_MSG
REM ==============================================
:SUB_STDOUT_MSG
    REM CALL :SUB_STDOUT_MSG "%param1%", %param2%, %param3%

    REM Instead of this stdout sub, we can use Unix 'tee.exe'
    REM but there is no 'line counter' feature like this sub
    REM   Call example : 
    REM     EDI_Generate_Stat_Csv | tee c:\temp\voir.txt
    REM   Def : 
    REM   Capture output from a program and also display the output to the screen, at the same time.

    REM %~1 => Expand %1 removing any surrounding quotes (")
    set msg=%~2
    set sendtoLog=%3
    set addCounter=%4

    If !msg!==. (
        REM Write empty line
        echo!msg!

        If !sendtoLog! EQU 1 (
            echo!msg! >> %log_file%
        )
    ) else (
        REM (a) Write comment line (b) add counter if any
        If !addCounter! EQU 1 (
            set /a msgCounter+=1
            set msg=!msgCounter! - !msg!

            REM Pad counter left for single digit
            If !msgCounter! LSS 10 (
                set msg=0!msg!
            )
        )

        REM Output to console
        echo !msg!

        REM Output to log
        If !sendtoLog! EQU 1 (
            echo !msg! >> %log_file%
        )
    )

    EXIT /B

B)以下是在“主逻辑”命令文件中调用“ SUB_STDOUT_MSG”的方法:

REM ... some other code here

REM ==============================================
REM                PROGRAM END
REM ==============================================
    set msg=.
    CALL :SUB_STDOUT_MSG !msg!, 1
    set msg="My programA - End"
    CALL :SUB_STDOUT_MSG !msg!, 1
    set msg="%date:~0,4%-%date:~5,2%-%date:~8,2% %time:~0,2%:%time:~3,2%:%time:~6,2%"
    CALL :SUB_STDOUT_MSG !msg!, 1
    set msg="+++++++++++++++"
    CALL :SUB_STDOUT_MSG !msg!, 1

    timeout 2 > Nul

REM Skip all SUB ROUTINE
    GOTO :EOF


REM ==============================================
REM                CALL SUB ROUTINE
REM ==============================================
:SUB_STDOUT_MSG
    REM echo calling sub %0

    CALL "C:\Utilitaires\Financement\Utility_Sub.cmd" SUB_STDOUT_MSG %*
    EXIT /B

:EOF

答案 3 :(得分:0)

如何提供目标标签作为被调用脚本的第一个要素?不过您需要修改被调用的dscript。

file1.bat(主要):

@echo off
echo/
echo File "%~0":  call "file2.bat" [no arguments]
call "file2.bat"
echo/
echo File "%~0":  call "file2.bat" :DEMO
call "file2.bat" :DEMO
echo/
echo File "%~0":  call "file2.bat" :DEMO A B C
call "file2.bat" :DEMO A B C

file2.bat(子):

@echo off
set "ARG1=%~1" & if not defined ARG1 goto :TEST
if "%ARG1:~,1%"==":" goto %ARG1%

:TEST
echo File "%~nx0", :TEST; arguments: %*
goto :EOF

:DEMO
echo File "%~nx0", :DEMO; arguments: %*
echo   before `shift /1`:
echo     "%%~0" refers to "%~0"
echo     "%%~1" refers to "%~1"
shift /1
echo   after  `shift /1`:
echo     "%%~0" refers to "%~0"
echo     "%%~1" refers to "%~1"
goto :EOF

输出:

>>> file1.bat

File "file1.bat":  call "file2.bat" [no arguments]
File "file2.bat", :TEST; arguments:

File "file1.bat":  call "file2.bat" :DEMO
File "file2.bat", :DEMO; arguments: :DEMO
  before `shift /1`:
    "%~0" refers to "file2.bat"
    "%~1" refers to ":DEMO"
  after  `shift /1`:
    "%~0" refers to "file2.bat"
    "%~1" refers to ""

File "file1.bat":  call "file2.bat" :DEMO A B C
File "file2.bat", :DEMO; arguments: :DEMO A B C
  before `shift /1`:
    "%~0" refers to "file2.bat"
    "%~1" refers to ":DEMO"
  after  `shift /1`:
    "%~0" refers to "file2.bat"
    "%~1" refers to "A"