我正在尝试从另一个调用一个bat文件,同时将目标变量保持为本地(主要是)。下面的代码是我失败的尝试,我想要的var缺失,但本地仍然存在。 我找到了一些关于使用setlocal here的信息,这就是我认为我拥有它的方式。此外,我用来推动var过去setlocal的信息是here。我很可能错过了这些东西。任何帮助表示赞赏!
呼叫蝙蝠:
@SET errmsg=Old Message
@CALL Target.bat TEST_JOB errmsg
@ECHO.jobname = %jobname%, but should be undefined
@IF DEFINED errmsg ECHO.Error occurred: %ERRORLEVEL% %errmsg%
目标蝙蝠:
@SETLOCAL
@ECHO OFF
:START
SET jobname=%~1
SET errmsgvar=%~2
:MAIN
CALL:ERROR "New Error Message"
ECHO.Should have never returned here
ENDLOCAL
:EXIT
@ECHO ON
@EXIT /b %ERRORLEVEL%
:ERROR "errorMesage"
ENDLOCAL & SET "%errmsgvar%=%~1"
ECHO.%errmsg% ^<-- Testing only, we don't know what the actual var will be
(GOTO) 2>NUL & GOTO:EXIT
结果:
C:\Projects\Batch>Caller.bat
New Error Message <-- Testing only, we don't know what the actual var will be
jobname = TEST_JOB, but should be undefined
Error occurred: 0 Old Message
为了清晰起见进行编辑:
我想在这里完成几件事......
看起来我的endlocal被忽略了,它只是在文件的末尾做了endlocal,这打破了事情
答案 0 :(得分:2)
正如Magoo所说,您的TEST_JOB值已正确清除。您的测试必须查看先前运行的保持结果。最好在CALL之前明确地清除你的呼叫球中的值,这样你就永远不会得到错误的结果..
由于你的逻辑缺陷,你的errmsg没有被设置。在我对(goto) 2>nul
提供一些介绍之后,再详细说明。
您正在尝试使用未广为人知的相对较新的(goto) 2>nul
技术。它实际上是exit /b
,除了附加的连接命令仍然执行,但在调用者的上下文中。我相信第一个发现发表在http://forum.script-coding.com/viewtopic.php?id=9050(我无法阅读),第一个已发布的英文帖子是http://www.dostips.com/forum/viewtopic.php?f=3&t=6491。
自DosTips发布以来,已经产生了许多有用的工具:
在您的代码中,您尝试在错误例程中使用ENDLOCAL,但这只会影响在例程中发出的SETLOCAL。您需要使用(goto) 2>nul
技巧之前来发布ENDLOCAL,以便ENDLOCAL在父上下文中正常工作。
:error "errormesage"
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~1"
goto :exit
)
我担心你的退回ERRORLEVEL。当发生错误时,我不认为它会返回您想要的值。
您必须记住,所有外部命令始终设置ERRORLEVEL是否存在错误。几乎所有内部命令在出错时都将ERRORLEVEL设置为非零,并且一些内部命令在成功时将ERRORLEVEL设置为0(但如果没有错误,则有些保留现有的ERRORLEVEL)。
最安全的做法是将您想要的错误号显式传递给:error例程,然后在退出时显式设置该值。这是一种方法:
:error "errMsg" errNum
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~1"
cmd /c exit %2
goto :exit
)
但是我会修改一些内容,这样无论是否有错误,你都会以同样的方式退出。如果出现错误,则调用下面的退出例程,并显示错误消息和错误号,并正确设置值。正常退出时,两个值都没有传入,因此errmsg变量被清除,例程返回当前的ERRORLEVEL(大概为0)。
调用脚本
@setlocal
@set errmsg=Old Message
@set "jobname="
@call target.bat TEST_JOB errmsg
@if defined jobname (
echo ERROR - jobname = %jobname%
) else (
echo SUCCESS - jobname is undefined
)
@if defined errmsg (
echo.Error occurred: %errorlevel% %errmsg%
) else (
echo No error occurred
)
<强> Target.bat 强>
@echo off
setlocal enableDelayedExpansion
:start
set jobname=%~1
set errmsgvar=%~2
:main
set /a "1/(%random% %% 3)" || call :exit !errorlevel! "Random error"
echo Success
call :exit
:exit [errNum] ["errMsg"]
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~2"
echo on
exit /b %1
)
:主代码在尝试除以零时随机增加33%的错误。
以下是一些示例输出,显示了两种可能的结果:
C:\test>test
Success
SUCCESS - jobname is undefined
No error occurred
C:\test>test
Divide by zero error.
SUCCESS - jobname is undefined
Error occurred: 1073750993 Random error
答案 1 :(得分:1)
完美地为我工作。
我相信您的测试集jobname
在某个阶段,因此您的setlocal/endlocal
帧只会恢复原始环境。
我建议您执行
set "jobname="
作为调用蝙蝠的第一行,以便在操作开始前强制jobname
清除。
答案 2 :(得分:0)
将第二行改为
ECHO.%errmsgvar%.....
匹配第3行到最后一行
作为解释...... ENDLOCAL&amp; SET“errmsgvar =%~1” 1.加载整行并且扩展%~1。 2.执行ENDLOCAL并结束本地化。 3. SET“errmsgvar =%~1”执行为...... SET“errmsgvar = WhateverWasIn%~1” 这种技术是隧道技术,是一种跨区域传递变量的方法。
答案 3 :(得分:0)
将您的第二个脚本更改为以下内容。如果在脚本末尾占用ENDLOCAL
。我相信ENDLOCAL
块中的:ERROR
仅适用于该块,而不是整个文件。
@SETLOCAL
@ECHO OFF
:START
SET jobname=%~1
SET errmsgvar=%~2
:MAIN
CALL:ERROR "New Error Message"
ECHO.Should have never returned here
ENDLOCAL
:EXIT
REM case insensitive test for errmsgvar.
IF DEFINED errmsgvar (
IF /I NOT "%errmsgvar%" == "" (
ENDLOCAL & SET "errmsg=%errmsg%"
)
)
@ECHO ON
@EXIT /b %ERRORLEVEL%
:ERROR "errorMesage"
ENDLOCAL & SET "errmsgvar=%~1"
SET "errmsg=%errmsgvar%"
ECHO.%errmsg% ^<-- Testing only, we don't know what the actual var will be
(GOTO) 2>NUL & GOTO:EXIT
输出变为(为清晰起见,额外的换行符):
Caller.bat
New Error Message <-- Testing only, we don't know what the actual var will be
jobname = TEST_JOB
Error occurred: 0 New Error Message