Batch file Windows批处理:can';t退出被调用的子例程-始终返回,即使goto:END

Batch file Windows批处理:can';t退出被调用的子例程-始终返回,即使goto:END,batch-file,Batch File,我有一个子例程,它被调用来检查ERRORLEVEL 该子例程调用其他子例程来记录MSG、发送电子邮件,然后退出脚本。它转到:END,然后在调用后返回stmt @echo off echo starting... call:checkTime echo +++ after CT GOTO:END :checkTime echo the time is %TIME% goto:END goto:EOF :END 这个问题措辞拙劣,但我想我能理解(特别是如果我专注于标题) 我对你问题的解释: @

我有一个子例程,它被调用来检查
ERRORLEVEL

该子例程调用其他子例程来记录MSG、发送电子邮件,然后退出脚本。它转到
:END
,然后在调用后返回stmt

@echo off
echo starting...
call:checkTime
echo +++ after CT
GOTO:END

:checkTime
echo the time is %TIME%
goto:END
goto:EOF

:END

这个问题措辞拙劣,但我想我能理解(特别是如果我专注于标题)

我对你问题的解释:

@echo off
rem If this is a false subroutine return: complete it
if "%1" == "return" goto %2
rem Do my usual business
rem . . .
rem Execute the subprogram as subroutine
set caller=main
set returnPoint=label23
subprogram param1 param2
:label23
rem Continue after subprogram return...
rem Do my business
rem . . .
rem To return to the caller:
%caller% return %returnPoint%
rem . . .
rem To terminate here, execute EXIT /B, GOTO :EOF, or just reach the end
在批处理文件的各个点上,检查ERRORLEVEL。无论何时检测到错误,都需要执行一些标准错误处理,然后退出批处理脚本。您试图创建一个子例程来执行标准处理,但该子例程返回给调用方,而不是退出脚本。您的问题是,如何强制您的错误处理例程退出,而不是返回调用方

回答:

@echo off
rem If this is a false subroutine return: complete it
if "%1" == "return" goto %2
rem Do my usual business
rem . . .
rem Execute the subprogram as subroutine
set caller=main
set returnPoint=label23
subprogram param1 param2
:label23
rem Continue after subprogram return...
rem Do my business
rem . . .
rem To return to the caller:
%caller% return %returnPoint%
rem . . .
rem To terminate here, execute EXIT /B, GOTO :EOF, or just reach the end
如果在被调用的子例程中未发生任何错误检测,则可以直接转到错误处理器,而不是调用它

如果希望能够调用该例程并从另一个调用的例程中退出,则可以继续使用
call
语句,但使用
exit
而不是
GOTO:EOF
GOTO:END
终止错误例程

回复评论的附录

是的,GOTO无法传递参数,被调用的例程将始终返回给调用方(除非例程以EXIT结束)

是的,EXIT将关闭当前的cmdshell,这通常会关闭控制台窗口

但是。。。您可以让批处理文件通过另一个CMD shell自行执行,以便EXIT不会关闭窗口

我看到的唯一潜在缺点是,一旦批处理文件(以及运行它的cmdshell)终止,对环境的更改就会丢失。这对你来说可能是个问题,也可能不是

@echo off
if "%~1" equ "_GO_" goto :main
cmd /c ^""%~f0" _GO_ %*^"
exit /b

:main
shift /1
echo %%1=%1  %%2=%2

echo before call
call :exitRoutine
:: should not get here
echo after call
exit /b

:exitRoutine
echo exiting batch file witin exitRoutine
exit

是的,这是预期的行为:通过
CALL
命令调用的子例程可能以三种不同的方式结束:执行
EXIT[/B]
、执行
GOTO:EOF
或刚刚到达文件末尾。这三种方式都会导致返回调用程序。同时,“GOTO命令现在接受一个目标标签:EOF,它将控制权转移到当前批处理脚本文件的末尾。这是一种不定义标签就退出批处理脚本文件的简单方法。”(从
GOTO/?
),因此第二种和第三种方法实际上是相同的

如果有时希望从子程序返回,但有时希望终止调用程序,则不能通过
CALL
执行子程序,而是以其他不同的方式执行子程序。如果要将参数传递给子程序,则该子程序必须是一个单独的.BAT文件,该文件将通过其名称执行,其中包含参数且不调用,例如:

subprogram param1 param2 ...
这样,为了让这个子程序“返回”到调用程序,它必须知道要返回哪个批处理文件以及它必须返回的行。该信息可由调用程序通过变量设置;调用程序还必须确定它是以正常方式运行,还是因为返回了false子例程。您可以这样做:

main.bat:

@echo off
rem If this is a false subroutine return: complete it
if "%1" == "return" goto %2
rem Do my usual business
rem . . .
rem Execute the subprogram as subroutine
set caller=main
set returnPoint=label23
subprogram param1 param2
:label23
rem Continue after subprogram return...
rem Do my business
rem . . .
rem To return to the caller:
%caller% return %returnPoint%
rem . . .
rem To terminate here, execute EXIT /B, GOTO :EOF, or just reach the end
子程序。bat:

@echo off
rem If this is a false subroutine return: complete it
if "%1" == "return" goto %2
rem Do my usual business
rem . . .
rem Execute the subprogram as subroutine
set caller=main
set returnPoint=label23
subprogram param1 param2
:label23
rem Continue after subprogram return...
rem Do my business
rem . . .
rem To return to the caller:
%caller% return %returnPoint%
rem . . .
rem To terminate here, execute EXIT /B, GOTO :EOF, or just reach the end

很抱歉,没有简单的方法可以做到这一点…

您不是真的在使用MS-DOS,是吗?Windows 2003中的DOS批处理脚本。没有“DOS”批处理脚本(在Windows Server 2003中)。这仍然是一个Windows批处理脚本,问题是什么?问题是:这是预期的行为吗?从结束返回?如果我转到错误例程,我不能将参数传递给例程,对吗?如果我退出,CMD窗口将关闭。正在发生的事情是预期的行为吗?即调用例程转到:结束返回给调用方?Thanks@chrys2012-我用我认为有效的解决方案更新了答案you@dbenham:+1个有趣的解决方案,戴夫!
退出
也可以通过这种方式在任何级别中断任何挂起的IF/FOR结构,并且该过程将在调用代码处继续。我可以建议宏
设置break=exit
?(我们已经在whilemacro中使用了这个想法)这个问题的措辞并不糟糕。很清楚。它指的是一个普遍和已知的问题!这不是提问者的问题。因此,不需要解释。下一次,如果你还没有理解这个问题,请不要试图回答,特别是在这个长度上。“这很烦人。”Apostolos——问题的主体应该能够独立存在,并且应该清楚地陈述问题。这个“问题”的主体仅说明OP正在做什么,并描述结果行为。它从不说明预期的行为是什么,也不提出问题。标题确实暗示了一个目标,但从来没有正确地说明它,也没有提出任何问题。“同时,”GOTO命令现在接受一个目标标签:EOF,它将控制权转移到当前批处理脚本文件的末尾。这是一种无需定义标签即可退出批处理脚本文件的简单方法。“我在每个子例程的末尾使用GOTO:EOF来退出子例程,而不是退出批处理脚本文件。@chrys2012-
GOTO:EOF
exit/B
是同义词-它们的作用完全相同。唯一的区别是
EXIT/B
可以选择指定ERRORLEVEL返回代码
GOTO:EOF
是在推出
EXIT/B
之前的旧语法。