2

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

因此,为了检测是否需要添加它,我使用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也没有效果。

4

3 回答 3

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

这就是我要使用的 - 其他方法与 mininterpreted 右括号问题相冲突。

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

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

!访问作为子句调用的变量的运行时值是一个非常奇怪的决定setlocal——就个人而言,我会使用类似ECHO on/off(ie EXPANSION on/off) 的开关,但我没有运行该项目。同样,本DATE可以配备一个/u开关以通用形式返回日期,但错过了机会(并且继续错过,在 NT4 之后的 17 年和 5 代之后......)

于 2013-05-23T04:50:35.420 回答
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 调用来转义该块。记住 % 变量永远不会延迟。

于 2013-05-22T16:32:46.160 回答
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
于 2013-05-23T11:57:19.857 回答