【问题标题】:CALL batch file environment variables discarded in Windows 7在 Windows 7 中丢弃的 CALL 批处理文件环境变量
【发布时间】:2014-07-24 03:19:52
【问题描述】:

我已经成功地使用 CALL 机制来允许一个批处理文件调用另一个批处理文件来设置环境变量。此代码已在 Windows XP 上运行了一年多。

但是,它在 Windows 7 上的工作方式似乎不同。变量存在于 EXIT /B 语句之前的第二个批处理文件中。但是,返回第一个批处理文件时它们不存在。

一些琐碎的示例似乎可以按预期工作,但大批量脚本却没有。

有没有人遇到过这个问题或知道任何解决方法?

【问题讨论】:

  • 确保第二个批处理文件没有setlocal 命令。
  • 第二个批处理脚本确实有几个SETLOCAL 命令。我正在使用ENDLOCAL 来确保在本地范围结束后设置局部变量。
  • 我需要能够在第二个批处理文件中使用SETLOCAL 才能使用ENABLEDELAYEDEXPANSION
  • 听起来像试错调试可能是唯一的方法。撕掉部分代码,直到问题消失,然后缩小确切的触发器。 (特别是,找出删除所有对 SETLOCAL 的调用是否会使问题消失。)

标签: windows batch-file cmd windows-7 environment-variables


【解决方案1】:

在多年的高级批处理脚本中,我从未见过 CALL 未能保存环境变量,除非调用的脚本(或标签)在 SETLOCAL 仍处于活动状态时设置了变量。在 CALL 终止时,CALL 内的每个活动 SETLOCAL 都有一个隐式 ENDLOCAL。

听起来您在 EXIT /B 之前已输入诊断消息以确认您的变量已定义。我会更进一步,在您的诊断消息之前添加多个 ENDLOCAL 语句。我怀疑您会在 EXIT /B 之前看到您的价值观消失。您可以根据需要添加任意数量的 ENDLOCAL。 ENDLOCAL 永远不会影响 CALL 之前发生的 SETLOCAL。

最可能的解释是您的脚本以某种方式从 XP 更改为 Win 7,或者您的 Win 7 环境中的某些上下文更改正在执行以前未公开的代码的某些方面。

【讨论】:

  • 非常感谢您了解这一点。今天我了解到它正在另一台 Windows 7 机器上工作,只是不是我的。对于每个 SETLOCAL 语句,我都有一个明确的 ENDLOCAL。我在 script2.bat 中的 EXIT /B 之前和 script1.bat 中的 CALL 语句之后立即转储环境。变量存在于第一个转储中。第二个转储中不存在变量。 (还有很多其他的转储...)
  • @Paul - 你在 script2 的最后一次转储之前添加了一堆额外的 ENDLOCAL 吗?在你告诉我你已经完成之前,我会认为你机器上的 script2 中仍然存在一个活动的 SETLOCAL,原因尚不清楚。
  • 我已经通过代码并将 setlocal 和 endlocal 语句配对。但我会再次检查。不过,这不应该导致它在一台机器上工作,而不是在另一台机器上工作。
  • 我相信你说你匹配了 SETLOCAL/ENDLOCAL。尽管如此,我希望您暂时添加一堆额外的 ENDLOCAL,因为我认为您将在 EXIT /B 之前丢失您的值。这要么证明我是对的,你仍然有一个活动的 SETLOCAL,要么证明我错了。至于为什么你可能只在一台机器上有一个活动的 SETLOCAL ? - 如果没有看到代码,我不可能猜到。但首先要做的是验证残留的 SETLOCAL 是问题(或不是问题)。不要依赖你的代码解析技能。做简单的测试。
  • 我在 EXIT /B 之前添加了五 (5) 个 ENDLOCAL 语句。结果相同。在 XP 上,新变量被保留。在 Windows 7 上,新变量被丢弃。 .bat 脚本文件位于服务器上。我在 XP 和 7 上的同一位置运行它。我没有在每台机器上运行不同的 .bat 脚本文件。
【解决方案2】:

试试这个:

(
   ENDLOCAL
   SET "_Var1=Some Variable You want to exist"
   SET "_Var2=Some Other Variable You want to exist"
   EXIT /b 0
)

还要确保从第 1 批中调用第 2 批,如下所示:

CALL "\\PathToBatch2\Batch2.cmd"

您也可以这样做:

CMD 一:

REM Script: Batch1
@(
   SETLOCAL
   ECHO OFF
   SET "_CallBatch2=C:\PathToBatch2\Batch2.cmd"
   SET "_SetCmd=CALL :SetCMD "
   SET "_RecievedVarList="
   SET "_RecievedVar1=" & REM  -- Note only done to show this is being created, normally you won't know or care what variables are being returned.
   SET "_eLvL=0"
)

CALL :Main

(
   ENDLOCAL
   EXIT /b %_eLvl%
)

:Main
   FOR %%A IN (CALL "%_CallBatch2%") DO (
      IF /I "%%~A" EQU "SET" (
         REM CALL %%A "%%~B" would work too
         %_SetCmd% %%~B
      ) ELSE (
         REM Looks like this was intended to be some output, show it.
         ECHO.%%A %%B
      )
   )
   FOR /F "Tokens=1*" %%A IN (%_RecievedVarList%) DO (
      REM ECHO the Variable's name and it's contents:
      CALL ECHO."%%~A" = "%%%%~A%%"
   )
GOTO :EOF

:SetCMD
   SET "%*"
   FOR /F "Tokens=1 Delims==" %A IN ("%*") DO (
     REM Store vars to output later to check their values.
     SET "_RecievedVarList=%_RecievedVarList% "%A""
   )
GOTO :EOF

.

CMD 二:

REM Script: Batch2
@(
   SETLOCAL
   ECHO OFF
)
CALL :Main
(
   ENDLOCAL
   EXIT /b %_eLvl%
)
:Main
   ECHO.SET "_RecievedVar1=This is Recieved Var 1"
   ECHO.SET "_RecievedVar2=This is Recieved Var 2"
GOTO :EOF

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-03
    • 2014-09-14
    • 2011-04-17
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    相关资源
    最近更新 更多