Windows пакетный сценарий: попытка извлечь версию Java путем зацикливания результатов команды с конвейером - PullRequest
1 голос
/ 19 марта 2020

Я хочу извлечь версию 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.

Я предполагаю, что здесь происходит какое-то плохое спасение, но я действительно не вижу, что не так.

1 Ответ

1 голос
/ 19 марта 2020

После расширения переменной строка:

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, поэтому остаток остается в силе (избегайте этих кавычек, чтобы не пришлось изменять другие escape-последовательности):

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...