1

I have a folder that contains multiple sub-directories

Directories example

The version format is [major].[minor].[update][phase][build], like 1.0.0d0. And valid phases are d(ev), a(lpha), b(eta), f(inal), please note d < a < b < f.

I'd like to get the latest version number which is 16.0.0a2 using batch script. I write such codes, but doesn't work, because the sub-directories are sorted by alphabetical order. So it will give a result 16.0.0d24.

SET BASEPATH=.....
SET TEMPFILE=%TEMP%\%~n0%RANDOM%
echo get latest export.
DIR /A:D /B /ON "%BASEPATH%" > "%TEMPFILE%"
FOR /F "usebackq delims=;" %%I IN ("%TEMPFILE%") DO (SET LATEST_VERSION=%%I)
echo LATEST_VERSION
phuclv
  • 37,963
  • 15
  • 156
  • 475
Seraph Cui
  • 11
  • 1

3 Answers3

2

The following script does what you want:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

set "LOC=%~1"
if not defined LOC set "LOC=."
set /A "PADV=100, PADB=10000"
set "SRCH=d" & set "REPL=@"

for /F "tokens=1,2,* delims=." %%A in ('
    dir /B /A:D /O:D /T:C "%LOC%" ^| ^
        findstr /I /R "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*[dabf][0-9][0-9]*"
') do (
    set /A "MAJOR=%%A+PADV, MINOR=%%B+PADV"
    for /F "tokens=1,* delims=DdAaBbFf" %%E in ("%%C") do (
        set /A "FIX=%%E+PADV, BUILD=%%F+PADB"
        set "PHASE=%%C" & set "PHASE=!PHASE:*%%E=!" & set "PHASE=!PHASE:~,1!"
        set "PHASE=!PHASE:%SRCH%=%REPL%!"
    )
    set "VERSION[!MAJOR!.!MINOR!.!FIX!!PHASE!!BUILD!]=%%A.%%B.%%C"
)

for /F "tokens=2 delims==" %%V in ('2^> nul set VERSION[') do (
    set "LATEST=%%V"
    echo(%%V
)
if defined LATEST echo Latest: & echo(%LATEST%

endlocal
exit /B

The basic concept is to adapt the version numbers so that (alpha-)numeric sorting provides the same result as alphabetic sorting. This can be achieved by adding a great number to every numeric part of the version numbers so that each one always has got the same number of digits. In addition, since the priority of the phase figure is not of alphabetical order, adequate replacements are done.

The core idea is taken from this answer and is credited to Aacini.

Community
  • 1
  • 1
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • I wonder why people won't use more powerful languages like python to do stuff like that. I understand when the batch file is a bootstrap to install some more powerful stuff, but that's not the case here. However: impressive answer!! – Jean-François Fabre Aug 03 '16 at 08:38
  • @Jean-FrançoisFabre, I guess it would also be quite easy for this task to be done by PowerShell, which is native to Windows, but the OP didn't tag the question accordingly... – aschipfl Aug 03 '16 at 09:35
1

Similar code to the one posted by aschipfl. Same value padding approach for each segment, just a different handling of name splitting and value padding.

@echo off
    setlocal enableextensions disabledelayedexpansion

    rem Give a path as argument or use current active directory
    for %%a in ("%~f1.") do set "target=%%~fa"

    rem Prepare variables to handle phase order correction and 
    rem storage of intermediate/final values
    set /a "_d=0", "_a=1", "_b=2", "_f=3"
    set "lastValue="
    set "lastVersion="

    rem %%a : Search the folders and split their name using dot as delimiter
    rem       %%a = major
    rem       %%b = minor
    rem       %%c = update + phase + build
    rem %%d : split %%c using [dabf] as delimters to obtain 
    rem       %%d = update
    rem       %%e = build
    rem %%f : split %%c using numbers as delimiters to obtain
    rem       %%f = phase 
    set "num=[0-9][0-9]*"
    for /f "tokens=1-3 delims=." %%a in ('
        dir /b /ad /o-d "%target%"
        ^| findstr /r /i /x /c:"%num%\.%num%\.%num%[dabf]%num%"
    ') do for /f "tokens=1,2 delims=dDaAbBfF" %%d in ( "%%c"
    )  do for /f "delims=0123456789" %%f in ( "%%c"
    )  do (
        rem Folder name has been splitted. Now, convert each of the segments
        rem to a numerical value, adding 1E6 to get a proper padding as all 
        rem values will be handled as strings to avoid limits in batch 
        rem arithmetic for values over 2^31
        rem Note that %%f is not being iterated here as the values to use 
        rem for phase padding have been previously defined
        for %%v in (
            %%a %%b %%d %%e
        ) do if not defined _%%v set /a "_%%v=1000000 + %%v"

        rem Obtain the properly padded version of the folder segments
        setlocal enabledelayedexpansion
        for /f "tokens=1,2" %%i in (
            "!_%%a!!_%%b!!_%%d!!_%%f!!_%%e! !lastValue!"
        ) do (
            endlocal
            rem Determine if we have found a newer version
            if "%%i" gtr "%%j" (
                set "lastValue=%%i"
                set "lastVersion=%%a.%%b.%%c"
            )
        )
    )

    if defined lastVersion (
        echo Latest version found is : %lastVersion%
    ) else (
        echo No matching folders
    )
Community
  • 1
  • 1
MC ND
  • 69,615
  • 8
  • 84
  • 126
1

the creation date should be a good criterium for sorting in this case:

...
echo get latest export.
FOR /F "delims=" %%I IN ('DIR /AD /B /OD /TC "%BASEPATH%"') DO SET "LATEST_VERSION=%%I"
echo %LATEST_VERSION%

dir-parameters:
/OD sort by date/time
/TC pick the creation date (instead of default "last modification date")
/AD show directories only
/B show just the names, no header, no sizes, dates etc, no summary.

If there max be other folders too, get your version-folders with dir ... "%basedir%\??.?.*" ("two chars, dot, one char, dot, whatever")

Stephan
  • 53,940
  • 10
  • 58
  • 91