批处理文件中的子程序

41

考虑以下代码:

@Echo off
ECHO Start
ECHO Calling SUB_A
CALL :SUB_A
ECHO Calling SUB_B
CALL :SUB_B

:SUB_A
    ECHO In SUB_A
    GOTO:EOF

:SUB_B
    ECHO In SUB_B
    GOTO:EOF

ECHO End

我希望得到这个输出:

Start
Calling SUB_A
In SUB_A
Calling SUB_B
In SUB_B
End

但我得到了这个:

Start
Calling SUB_A
In SUB_A
Calling SUB_B
In SUB_B
In SUB_A

我在这里做错了什么?

5个回答

69
如果你想从一个CALL语句中返回,你可以使用EXIT命令并带上/B参数(因为仅使用"EXIT"命令会终止批处理文件)。
例如:
CALL :SUB_ONE
CALL :SUB_TWO

GOTO :EOF

:SUB_ONE
ECHO Hello from one
EXIT /B

:SUB_TWO
ECHO Hello from two
EXIT /B

:EOF

7
相较于使用goto :EOF,我更喜欢这种方法,因为它可以添加一个返回值作为ERRORLEVEL:exit /B %RetVal% - SvenS
8
注意:您不应该定义 EOF 标签。GOTO :EOF 可以直接使用。另外请注意,您正在调用 :EOF,而您只能定义 EOF,然后通过 GOTO EOF 来调用它。 - Nux
需要在“CALL”和子程序名称之间加上冒号。我以前从未使用过它们,但在这里使用后它就起作用了。 - user1473461

22

CALL :SUB_B这一行返回后,脚本继续执行接下来的几行:

:SUB_A           # no effect from this one
ECHO In SUB_A    # prints message

如果你想要在调用后停止程序,你需要插入GOTO:EOF

批处理文件不是结构化的程序;它们是一系列指令,具有类似BASIC的GOTO和CALL功能。


6
在你的代码行CALL :SUB_B之后,批处理文件会继续执行到SUB_A。如果不想这样,需要在那里加一行GOTO命令。

2

我想插一句嘴:

我认为DOS文件(或DOS批处理文件)应该始终按照以下方式编写:

[ Main Program ]

EXIT

[ All Subroutines ]

以这种方式,你永远不会陷入子程序部分。
此外,在每个部分之前、期间和可能之后始终使用REM语句,以便始终知道该部分将要执行什么操作。
最后但并非最不重要的是,看看是否可以编写一个批处理文件,使其变得更加通用,这样你就可以将其放在一边,并在需要时再次使用它。
只是我认为这很常识,你可能已经知道了。:-)
哦!对不起!忘记发布我写的小睡眠子例程了。在这里! :-)
REM
REM Calling the Sleeper subroutine
REM
call :sleeper
exit

REM
REM Sleeper subroutine
REM
REM qna = Questions and Answers
REM
REM Interestingly - you can NOT use a '>'
REM Because DOS uses it for redirection!
REM Instead - use a question mark (?)
REM
:sleeper
set /p qna=Press return to continue or 'q' to stop ?
if [%qna%] == [q] (
    echo Exiting....please wait.
    exit
    )

goto :eof

0

不要使用 EXIT!

示例:

@rem a.bat
@echo off
echo a.bat
timeout /t 1

call b.bat

call c.bat

@rem b.bat
@echo off
echo b.bat
timeout /t 1

call :subB
rem call to c.bat will fail if using "exit" instead of "goto :end"
goto :end

:subB
echo subB
timeout /t 1
exit /b

:end

@rem c.bat
@echo off
echo c.bat
timeout /t 1

“exit”立即中止调用链!


1
十年前aikeru已经详细解释过了。使用名为 :end 的标签是多余的,因为总是存在隐式标签 :eof - jeb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接