如何在Batch for循环中获取所有tokens以完整获取JavaHome路径?
首先,你的核心问题可以通过调整for /f的tokens参数轻松解决,不需要逐个列出%%a、%%b这类变量,也完全没必要额外嵌套循环。
问题根源
你原来的脚本里已经用到了tokens=3*,但误解了它的作用:
3表示提取第3个分隔后的token*的作用是把**从第3个token之后的所有内容(包括空格)**直接赋值给最后一个变量(也就是这里的%%b)
所以你根本不需要把%%a和%%b拼接起来,直接用%%b就能拿到完整的JavaHome路径!
修正后的完整脚本
@echo off setlocal enabledelayedexpansion :: 获取对应JRE/JDK的CurrentVersion for /f "skip=2 tokens=3" %%x in ('reg query "HKLM\SOFTWARE\JavaSoft\%~1" /v CurrentVersion') do set JavaTemp=%%x :: 获取带空格的完整JavaHome路径 for /f "skip=2 tokens=3*" %%a in ('reg query "HKLM\SOFTWARE\JavaSoft\%~1\!JavaTemp!" /v JavaHome') do set JAVA_HOME=%%b echo !JAVA_HOME! endlocal
关键细节说明
tokens=3*的正确用法:
当注册表返回的行格式类似JavaHome REG_SZ C:\Program Files\Java\jdk1.8.0_301时,skip=2跳过前两行无关内容,tokens=3*会把第3个token(REG_SZ)赋值给%%a,而从第4个开始的所有内容(也就是带空格的完整路径)直接赋值给%%b,所以直接取%%b就得到了完整路径。延迟扩展的作用:
脚本里启用了setlocal enabledelayedexpansion,并用!变量名!来引用变量,这是为了避免后续如果把逻辑放到if/for代码块中时,普通%变量名%会提前解析导致的取值错误,属于Batch脚本的常用最佳实践。关于
%%*的误区:
你尝试的set JAVA_HOME=%%*无效是因为%%*是批处理脚本的参数通配符(代表所有传入的脚本参数),在for /f的循环变量里并不支持这种写法,正确捕获剩余内容的方式就是用tokens=N*的格式。是否需要嵌套循环?
完全不需要。当前的两次独立for /f已经能完成需求,嵌套循环一般用于处理多层次的复杂数据结构,这里用两次注册表查询就足够解决问题,没必要复杂化。
内容的提问来源于stack exchange,提问作者Sean McCallum

