В пакетном файле, запущенном из Windows, выберите последнюю версию приложения, используя имя каталога

Я использую портативное приложение, которое имеет обновления довольно часто. Проблема в том, что в каждой версии приложения есть папка с именем "processing-xyz". Каждый раз, когда я устанавливаю новую версию, мне нужно связать файлы с новой версией, которая находится в другой папке. Чтобы обойти эту неприятность, я хочу связать тип файла "*.pde" с командным файлом.

Имена папок идут следующим образом

  • Обработка-3.2.1
  • Обработка-3.2.2
  • и т.п.

Я создал этот небольшой пакетный скрипт, который получает исполняемый файл из последней версии.

@echo off

for /f "delims=" %%D in ('dir processing* /a:d /b /o-n') do (
  set currentFolder=%%~fD

  :: Check if environment variable already set
  if not %currentFolder%==%processing% (
    :: Set environment variable processing
    setx processing %currentFolder%
  )

  %currentFolder%/processing.exe %1
  goto :eof
)

Он работает при запуске из командной строки, но не в Windows. Есть ли конкретная причина? Кроме того, есть ли способ оптимизировать этот код?

Спасибо

3 ответа

Решение

Предположим, что номера версий всегда состоят из одной цифры, я бы сделал это следующим образом:

@echo off

rem // Reset variable:
set "currentFolder="
rem /* Loop through the folders in ascending order, overwrite the variable
rem    in each iteration, so it holds the highest version finally: */
for /f "delims=" %%D in ('dir /B /A:D /O:N "processing-*.*.*"') do (
    set "currentFolder=%%~fD"
)

rem // Check if environment variable is already set:
if not "%processing%"=="%currentFolder%" (
    rem // Set environment variable `processing`:
    setx processing "%currentFolder%"
)

rem // Execute `processing.exe`:
"%currentFolder%/processing.exe" "%~1"

Если отдельные номера версий могут состоять из более чем одной цифры (максимум четыре здесь), используйте это:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem /* Assign each found folder to a variable called `$ARRAY_X_Y_Z`, where `X`, `Y`, `Z`
rem    are zero-padded variants of the original numbers `x`, `y`, `z`, so for instance,
rem    a folder called `processing-4.7.12` is stored in variable `$ARRAY_0004_0007_0012`: */
for /F "tokens=1-4 delims=-. eol=." %%A in ('
    dir /B /A:D "processing-*.*.*" ^| ^
    findstr /R /I "^processing-[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*$"
') do (
    rem // Perform the left-side zero-padding here:
    set "MAJ=0000%%B" & set "MIN=0000%%C" & set "REV=0000%%D"
    set "$ARRAY_!MAJ:~-4!_!MIN:~-4!_!REV:~-4!=%%A-%%B.%%C.%%D"
)
rem // Reset variable:
set "currentFolder="
rem /* Loop through the output of `set "$ARRAY_"`, which returns all variables beginning
rem    with `$ARRAY_` in ascending alphabetic order; because of the zero-padding, where
rem    alphabetic and alpha-numeric orders become equivalent, the item with the greatest
rem    version number item is iterated lastly, therefore the latest version is returned: */
for /F "tokens=1,* delims==" %%E in ('set "$ARRAY_"') do (
    set "currentFolder=%%F"
)
endlocal & set "currentFolder=%currentFolder%"

rem // The rest of the script os the same as above...

Вы также можете найти похожие подходы здесь:

Не проверено (отредактировано: должно обрабатывать случаи, когда младшие версии имеют больше цифр):

@echo off
setlocal enableDelayedExpansion

    set /a latest_n1=0
    set /a latest_n2=0
    set /a latest_n3=0

for /f "tokens=2,3* delims=-." %%a in ('dir processing* /a:d /b /o-n') do (
    set "current_v=%%a.%%b.%%c"
    set /a "current_n1=%%a"
    set /a "current_n2=%%b"
    set /a "current_n3=%%c"

    if !current_n1! GTR !latest_n1! (

        set /a latest_n1=!current_n1!
        set /a latest_n2=!current_n2!
        set /a latest_n3=!current_n3!

        set "latest_v=!current_v!"
    ) else  if !current_n1! EQU !latest_n1! if !current_n2! GTR !latest_n2! (

        set /a latest_n1=!current_n1!
        set /a latest_n2=!current_n2!
        set /a latest_n3=!current_n3!

        set "latest_v=!current_v!"
    ) else if !current_n1! EQU !latest_n1! if !current_n2! EQU !latest_n2! if !current_n3! GTR !latest_n3! (

        set /a latest_n1=!current_n1!
        set /a latest_n2=!current_n2!
        set /a latest_n3=!current_n3!

        set "latest_v=!current_v!"
    )

)

echo latest version=processing-%latest_v%
@echo off

for /f "delims=" %%D in ('dir processing* /a:d /b /o-n') do (
 if "%processing%" neq "%cd%\%%F" setx processing "%cd%\%%F" >nul
 .\%%F\processing.exe %1
 goto :eof
)

эквивалентный код - почти.

Первая проблема - :: Форма комментариев не должна использоваться в блоке кода (заключенная в скобки серия операторов), так как :: на самом деле это метка, которая сама по себе звездочка с двоеточием. Поскольку это метка, она завершает блок.

Следующая проблема - внутри блока кода, %var% refers to the value ofвар**as it stood when thefor` был обнаружен ** - не так, как он изменяется внутри цикла.

Следующая проблема - как отметили другие, /o-n производит последовательность по имени, так 10 скорее всего отсортировать после 9 (так как сортировка обратная). Я не изменил это в коде замены, но /o-d сортировка по обратной дате может лучше подходить для вашего приложения.

Теперь о том, как работает ваш код.

Первый, processing устанавливается на любой установленный последний запуск. Если это отличается от значения, рассчитанного из этого прогона, то setx новое значение. Причудливо, setx не set значение в текущем cmd экземпляр, только для экземпляров, созданных в будущем.

Затем вы пытаетесь выполнить свой процесс и затем выходите из пакета с goto :eof, Единственная проблема в том, что %currentfolder% это не значение, измененное циклом, потому что оно должно быть в блоке кода. Похоже, что изменится ::-comments сломали блок и где currentfolder используется в вашем коде, он находится за пределами блока.

Вместо этого используйте .\%%F\executablename что означает "из текущего имени каталога (.); Подкаталог %%F;filenametoexecute" - обратите внимание, что"\"является разделителем каталогов в окнах, '/' указывает на переключатель.

Другие вопросы по тегам