Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Batch file 跨文件批处理使用set/endlocal时遇到困难_Batch File - Fatal编程技术网

Batch file 跨文件批处理使用set/endlocal时遇到困难

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

我试图从一个bat文件调用另一个bat文件,同时保持目标变量自身的局部性(大部分)。下面的代码是我失败的尝试,我想要的变量丢失了,但是本地变量仍然存在。 我发现了一些关于使用setlocal的信息,我想这就是我所知道的。另外,我用来将var推过setlocal的信息是。很有可能我遗漏了一些东西。感谢您的帮助

呼叫蝙蝠:

@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未按预期工作。再次感谢。