使用setlocal后如何设置变量NORMALLY?

时间:2013-05-22 16:22:15

标签: batch-file

我正在尝试创建一个简单的批处理文件(“javapath.bat”),以便在需要时将Java编译器添加到路径中,这样它就不会一直在路径上。我还希望能够在其他构建脚本中执行@call javapath.bat之类的操作,以便在需要时自动添加路径。由于这些将在edit-save-compile-run grind期间重复运行,这意味着javapath.bat需要检查Java是否已经在路径上并且如果是,则不会读取它,因为显然Microsoft认为这是一个好主意让路径变量有很多愚蠢的重复。

因此,要检测是否需要添加,我使用setlocal启用“命令扩展”,以便我可以使用环境变量字符串替换。丑陋的工作正常。

然后我使用endlocal所以我实际上可以设置环境变量,而不会在脚本结束时恢复更改。那不行。或者,它肯定会阻止变量的变量被恢复,但这不正常:它完全阻止它们在本地可见,但它们之后仍然可见。

@echo off
setlocal enableextensions
if "%path:jdk1=%"=="%path%" (
    endlocal
    set ANT_HOME=C:\Program Files\Java\ant
    set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_07
    path %ANT_HOME%\bin;%path%
    path %JAVA_HOME%\bin;%path%
)

在上述之后,正确设置了ANT_HOME和JAVA_HOME。但对PATH的唯一改变是“\ bin;”已经被添加到它之前,因为在脚本期间设置的变量在之后都不可见(因此ANT_HOME和JAVA_HOME是空白的,并且忘记了对PATH的第一次更改)。因此,运行两次可以将Java添加到路径中,而不是Ant。我可以对路径进行两次硬编码,但这种行为是如此奇怪和荒谬,而且我已经坚持了一个小时。

编辑:添加enabledelayedexpansion也没有效果。

3 个答案:

答案 0 :(得分:4)

@echo OFF
ECHO starting   %PATH%
if "%path:jdk1=%"=="%path%" CALL :addjava
ECHO.
ECHO resulting  %PATH%
GOTO :eof

:addjava
set ANT_HOME=C:\Program Files\Java\ant
set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_07
SET "path=%ANT_HOME%\bin;%JAVA_HOME%\bin;%path%"
GOTO :eof

这是我使用的 - 其他方法与误解的闭括号问题相冲突。

理解这种奇怪行为的关键是历史。 Batch始终将任何%var%的分析时间值替换为代码,然后验证结果并在有效时执行。随着语言的发展,有必要保持与现有批次的兼容性,因此您只能添加新的关键字和功能,而不是删除或更改功能。

因此,添加了调用内部子例程的容量,并在'&'的单行上级联指令,并通过附上指令允许iffor的多行指令在括号中引入了,并且需要在文件或目录名中使用空格和其他分隔符的能力,批处理语言开始有一些小怪癖。

!访问作为setlocal子条款调用的变量的运行时值是一个非常奇怪的决定 - 就个人而言,我使用了像{{{{}}这样的开关。 1}}(即ECHO on/off)但我没有运行该项目。以同样的方式,EXPANSION on/off本来可以配备DATE开关以通用形式返回日期,但机会被遗漏(并且在NT4和5次wingenerations后17年仍然被遗漏后来...)

答案 1 :(得分:3)

if块中的所有内容都可以一次性评估。因此%ANT_HOME%设置ANT_HOME 后无效,您需要输入延迟扩展:

setlocal enabledelayedexpansion

if "%path:jdk1=%"=="%path%" (
    set ANT_HOME=C:\Program Files\Java\ant
    set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_07
    path = !ANT_HOME!;!path!
    path = !JAVA_HOME!;!path!
)
:: important trick since they evaluate together %path% is still
:: what is inside local
endlocal & path %path%
path

否则没有延迟扩张。此外,您还需要在使用endlocal的undeleyed调用时使用它来逃避阻止。记住%变量永远不会延迟。

答案 2 :(得分:3)

正如其他人所指出的那样,除非在非常特殊的情况下,否则应该已启用扩展。您只需要消除SETLOCAL并稍微重构IF,以便在PATH已经设置时退出脚本。

@echo off
if not "%path:jdk1=%"=="%path%" exit /b
set "ANT_HOME=C:\Program Files\Java\ant"
set "JAVA_HOME=C:\Program Files\Java\jdk1.7.0_07"
path %ANT_HOME%\bin;%path%
path %JAVA_HOME%\bin;%path%

如果您确实需要启用扩展程序,那么

@echo off
setlocal enableExtensions
if not "%path:jdk1=%"=="%path%" exit /b
endlocal
set "ANT_HOME=C:\Program Files\Java\ant"
set "JAVA_HOME=C:\Program Files\Java\jdk1.7.0_07"
path %ANT_HOME%\bin;%path%
path %JAVA_HOME%\bin;%path%

如果您的脚本还有其他工作要做,那么

@echo off
setlocal enableExtensions
if not "%path:jdk1=%"=="%path%" goto :skip
endlocal
set "ANT_HOME=C:\Program Files\Java\ant"
set "JAVA_HOME=C:\Program Files\Java\jdk1.7.0_07"
path %ANT_HOME%\bin;%path%
path %JAVA_HOME%\bin;%path%

:skip
REM carry on with additional code as needed