Batch file 跨文件批处理使用set/endlocal时遇到困难
我试图从一个bat文件调用另一个bat文件,同时保持目标变量自身的局部性(大部分)。下面的代码是我失败的尝试,我想要的变量丢失了,但是本地变量仍然存在。 我发现了一些关于使用setlocal的信息,我想这就是我所知道的。另外,我用来将var推过setlocal的信息是。很有可能我遗漏了一些东西。感谢您的帮助 呼叫蝙蝠:Batch file 跨文件批处理使用set/endlocal时遇到困难,batch-file,Batch File,我试图从一个bat文件调用另一个bat文件,同时保持目标变量自身的局部性(大部分)。下面的代码是我失败的尝试,我想要的变量丢失了,但是本地变量仍然存在。 我发现了一些关于使用setlocal的信息,我想这就是我所知道的。另外,我用来将var推过setlocal的信息是。很有可能我遗漏了一些东西。感谢您的帮助 呼叫蝙蝠: @SET errmsg=Old Message @CALL Target.bat TEST_JOB errmsg @ECHO.jobname = %jobname%, but s
@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
@SETLOCAL
@回音
:开始
设置作业名=%~1
设置errmsgvar=%~2
:MAIN
调用:错误“新建错误消息”
埃科,我不应该再回来了
端部
:退出
@呼应
@退出/b%ERRORLEVEL%
:错误“errorMesage”
ENDLOCAL&设置“%errmsgvar%=%~1”
回显。%errmsg%^将最后第二行更改为
ECHO.%errmsgvar%.....
匹配第三行到最后一行
作为解释。。。
ENDLOCAL&设置“errmsgvar=%~1”
1.整条线路已加载并扩展%1。
2.执行ENDLOCAL并结束本地化。
3.集“errmsgvar=%~1”作为。。。
设置“errmsgvar=WhateverWasIn%~1”
这种技术是隧道技术,是一种跨地区传递变量的方法。将第二个脚本更改为以下内容。If解释脚本末尾的ENDLOCAL
。我相信:ERROR
块中的ENDLOCAL
只针对该块,而不是整个文件
@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
@SETLOCAL
@回音
:开始
设置作业名=%~1
设置errmsgvar=%~2
:MAIN
调用:错误“新建错误消息”
埃科,我不应该再回来了
端部
:退出
errmsgvar的REM不区分大小写测试。
如果定义了errmsgvar(
如果/I不是“%errmsgvar%”(
ENDLOCAL&设置“errmsg=%errmsg%”
)
)
@呼应
@退出/b%ERRORLEVEL%
:错误“errorMesage”
ENDLOCAL&设置“errmsgvar=%~1”
设置“errmsg=%errmsgvar%”
ECHO.%errmsg%^对我来说非常有效
我相信您的测试集jobname
在某个阶段,因此您的setlocal/endlocal
框架只是恢复了原始环境
我建议你执行死刑
set "jobname="
作为调用bat的第一行,在操作开始之前强制清除jobname
。正如Magoo所说,测试作业值已正确清除。您的测试必须查看上次运行的延迟结果。最好在调用之前明确清除调用bat中的值,这样就永远不会得到错误的结果
由于逻辑中存在缺陷,未设置errmsg。在我介绍了(goto)2>nul
之后,我将介绍更多内容
您正在尝试使用一种相对较新的(goto)2>nul
技术,这种技术并不广为人知。它实际上是一个退出/b
,除了在调用方的上下文中仍然执行附加的连接命令之外。我相信第一个发现发表在(我看不懂),第一个已知的英文帖子发表在
自DosTips发布以来,产生了许多有用的工具:
- -一个函数,用于安全返回通过端部局部屏障的任何值。这个函数是
- -部分模拟unix here doc功能
- -批处理脚本中的有效异常处理
在代码中,您尝试在错误例程中使用ENDLOCAL,但这只影响在例程中发出的SETLOCAL。在发出ENDLOCAL之前,需要使用(goto)2>nul
技巧,以便ENDLOCAL在父上下文上正常工作
:error "errormesage"
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~1"
goto :exit
)
我很担心你的水平。我认为当出现错误时,它不会返回您想要的值
您必须记住,无论是否存在错误,所有外部命令都会设置ERRORLEVEL。几乎所有内部命令在出错时都将ERRORLEVEL设置为非零,一些内部命令在成功时将ERRORLEVEL设置为0(但如果没有错误,一些内部命令将保留现有ERRORLEVEL)
最安全的做法是将所需的错误号显式传递到:error例程中,然后在退出时显式设置该值。以下是一种方法:
:error "errMsg" errNum
(
(goto) 2>nul
endlocal
set "%errmsgvar%=%~1"
cmd /c exit %2
goto :exit
)
但是我会修改一些东西,这样无论是否有错误,您都可以以相同的方式退出。如果发生错误,则调用下面的: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
)
@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
)
Target.bat
@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
)
@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
这一行只是为了验证传递给target.bat的变量名errmsg实际上是由前一行设置的。据我所知,这就是如何将数据推过endlocal屏障的方法。@someone迷路了,我在回答中做了解释。在里面放几个回音语句,看看我的意思。谢谢你的回答!我发现你的陈述都是正确的;endlocal放置不正确,errorlevel未按预期工作。再次感谢。