1

我想在我的机器上提取 Java 版本。
1/ 我安装了 Oracle Java 8,命令where java输出如下:

C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe

2/ 命令java -version输出:

java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)

3/ 命令java -version 2>&1 | find "version"输出:

java version "1.8.0_221"

所以我想做与批处理文件中的最后一个命令完全相同的事情。因此,在批处理文件中,我有类似于步骤 2 的代码:

@echo off & setLocal enableExtensions enableDelayedExpansion
set /a count=0
for /f "tokens=*" %%j in ('where java') do (
    set /a count+=1
    set JAVA[!count!]=%%j
    call :echo_java
)
goto :eof

:echo_java
    set java_cmd="!JAVA[%count%]!" -version
    for /f "tokens=*" %%v in ('%java_cmd% 2^>^&1') do echo %%v
    exit /b 0

但是,一旦我将函数修改为:echo_java相当于第 3 步,如下所示:

:echo_java
    set java_cmd="!JAVA[%count%]!" -version
    for /f "tokens=*" %%v in ('%java_cmd% 2^>^&1 ^| find "version"') do echo %%v
    exit /b 0

我收到此错误:

'C:\Program' is not recognized as an internal or external command, operable program or batch file.

我想这里发生了一些不好的转义,但我真的看不出有什么问题。

4

1 回答 1

1

变量扩展后的行:

for /f "tokens=*" %%v in ('%java_cmd% 2^>^&1 ^| find "version"') do echo %%v

扩展为:

for /f "tokens=*" %%v in ('"C:\Program Files (x86)\...\java.exe" 2^>^&1 ^| find "version"') do echo %%v

所以要执行的命令行以 .for /F开头和结尾"

for /F用于cmd /c执行该命令行,该命令行会删除周围的",从而将其留在后面:

C:\Program Files (x86)\...\java.exe" 2>&1 | find "version

这显然是不正确的语法。

为避免这种情况,请更改命令行,使其不被引号包围(通过在此处移动重定向部分):

for /f "tokens=*" %%v in ('2^>^&1 %java_cmd% ^| find "version"') do echo %%v

或者,提供可以通过 删除的显式引号cmd /C,以便其余部分保持有效(转义这些引号以便不必更改其他转义序列):

for /f "tokens=*" %%v in ('^"%java_cmd% 2^>^&1 ^| find "version"^"') do echo %%v

此外,我想建议稍微修改一下整个脚本(请参阅所有rem备注):

@echo off
rem /* Begin the script with delayed expansion disabled as it might lead to problems
rem    during expansion of `for` meta-variables in case the values contain `!`: */
setlocal EnableExtensions DisableDelayedExpansion
rem // Use quoted `set` syntax (this requires the command extensions to be enabled):
set /A "count=0"
for /F "tokens=*" %%j in ('where java') do (
    set /A "count+=1"
    rem // Enable delayed expansion only when needed, like for variable `count` here:
    setlocal EnableDelayedExpansion
    rem /* (Mis-)use a `for` loop to make the value of `!count!` available even when
    rem    delayed expansion is disabled, hence after `endlocal` then: */
    for %%c in (!count!) do endlocal & set "JAVA[%%c]=%%j"
    rem /* Pass an argument over to the sub-routine rather than using variables
    rem    globally; in this situation this even does not need delayed expansion: */
    call :ECHO_JAVA "%%j"
)
endlocal
goto :EOF

:ECHO_JAVA
    rem /* Explicitly disable delayed expansion in the sub-routine, so you may call
    rem    it even from a code section with delayed expansion enabled: */
    setlocal DisableDelayedExpansion
    rem /* Use the sub-routine argument (`%~1`) herein, with explicit control of
    rem    quotation (`~` removes potential quotes, then we explicitly add such): */
    for /F "tokens=*" %%v in ('2^>^&1 "%~1" -version ^| find "version"') do echo(%%v
    endlocal
    exit /B 0
于 2020-03-19T00:39:54.617 回答