Search code examples
batch-filefor-looppathstring-parsing

How to get Java version in a batch script subroutine?


From this question:

for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do (
    @echo Output: %%g
    set JAVAVER=%%g
)

How can I put this into a subroutine and call it, passing a path to the java executable? Here's an example of my problem:

@echo off
setlocal enabledelayedexpansion

call :GET_JAVA_VER "java"
goto END

:GET_JAVA_VER
    for /f "tokens=3" %%g in ('%1 -version 2^>^&1 ^| findstr /i "version"') do @echo %%g
    %1 -version 2>&1 | findstr /i "version"
goto :EOF

:END
    endlocal

This outputs:

The filename, directory name, or volume label syntax is incorrect.
java version "10.0.1" 2018-04-17

It seems to me that the for loop is evaluating the parameter (%1) differently.

What's the difference?


EDIT

Possible duplicate of Java Version in a batch file

According to this answer, if that is indeed the problem, I would have to somehow transform the passed in path by adding quotes around each directory containing spaces. That sounds like a pain and I'm hoping there's another explanation; I still don't get why in this case just passing in "java" doesn't work.

(Note: using usebackq and back-quotes makes no difference)


Solution

  • It seems that piping the output to findstr was stripping the quotes for some reason. I deduce this because when I removed the ^| findstr /i "version" portion, this:

    @echo off
    setlocal enabledelayedexpansion
    
    call :GET_JAVA_VER "java"
    goto END
    
    :GET_JAVA_VER
        for /f "tokens=3" %%g in ('%1 -version 2^>^&1') do @echo %%g
    goto :EOF
    
    :END
        endlocal
    

    Outputs this:

    "10.0.1"
    Runtime
    64-Bit
    

    This modified script works (with full paths as well):

    @echo off
    setlocal enabledelayedexpansion
    
    call:GET_JAVA_VER "java"
    goto END
    
    :GET_JAVA_VER
        for /f "tokens=3" %%g in ('%~1 -version 2^>^&1') do (
            echo %%~g
            rem Stop after first line
            goto :EOF
        )
    goto :EOF
    
    :END
        endlocal