In pure batch scripting, you could use the following code snippet:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
> "versions.tmp" (
for /F "usebackq tokens=1,2,3,4 delims=." %%I in ("versions.txt") do (
set "ITEM1=000%%I" & set "ITEM2=000%%J" & set "ITEM3=000%%K" & set "ITEM4=000%%L"
echo !ITEM1:~-4!.!ITEM2:~-4!.!ITEM3:~-4!.!ITEM4:~-4!^|%%I.%%J.%%K.%%L
)
)
< "versions.tmp" (
for /F "tokens=2 delims=|" %%S in ('sort') do (
echo %%S
)
)
del /Q "versions.tmp"
endlocal
exit /B
This creates a temporary file, which contains the original line, prefixed with padded version numbers and a separtor |
. Padded numbers means that each component is padded with leading zeros to four digits. Here is an example based on youe sample data:
0003.0006.0004.0002|3.6.4.2
0003.0006.0005.0001|3.6.5.1
0003.0006.0005.0010|3.6.5.10
0003.0006.0005.0011|3.6.5.11
0003.0006.0005.0012|3.6.5.12
0003.0006.0005.0013|3.6.5.13
0003.0006.0005.0002|3.6.5.2
0003.0006.0007.0001|3.6.7.1
0003.0006.0007.0010|3.6.7.10
0003.0006.0007.0011|3.6.7.11
0003.0006.0007.0002|3.6.7.2
0003.0006.0007.0003|3.6.7.3
This temporary file is then passed over to sort
which does a purely alphabetic sorting. Since the numbers are padded, the sort order equals the true alphanumeric order. Here is the sorting result using the above example:
0003.0006.0004.0002|3.6.4.2
0003.0006.0005.0001|3.6.5.1
0003.0006.0005.0002|3.6.5.2
0003.0006.0005.0010|3.6.5.10
0003.0006.0005.0011|3.6.5.11
0003.0006.0005.0012|3.6.5.12
0003.0006.0005.0013|3.6.5.13
0003.0006.0007.0001|3.6.7.1
0003.0006.0007.0002|3.6.7.2
0003.0006.0007.0003|3.6.7.3
0003.0006.0007.0010|3.6.7.10
0003.0006.0007.0011|3.6.7.11
Finally, if you want to return the latest version number only, echo %%S
by set "LVER=%%S"
and place echo !LVER!
after the closing )
of the second for /F
loop.
Update:
Here is a solution that does not produce any temporary files, but uses a pipe |
instead. Since a pipe creates new cmd
instances for both left and right sides, and due to the fact that the (console) outputs are built in tiny bits and that there are multiple arithmetic operations done, it is rather slow:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
(
for /F "usebackq tokens=1,2,3,4 delims=." %%I in ("versions.txt") do @(
set /A "10000+%%I" & echo( ^| set /P "=."
set /A "10000+%%J" & echo( ^| set /P "=."
set /A "10000+%%K" & echo( ^| set /P "=."
set /A "10000+%%L" & echo(
)
) | (
for /F "tokens=1,2,3,4 delims=." %%S in ('sort') do @(
set /A "%%S-10000" & echo( ^| set /P "=."
set /A "%%T-10000" & echo( ^| set /P "=."
set /A "%%U-10000" & echo( ^| set /P "=."
set /A "%%V-10000" & echo(
)
)
endlocal
exit /B
Left Side of the Pipe:
Instead of the substring expansion syntax like in the above approach using a temporary file, I add 10000
to every component of the version numbers (similar to Aacini's answer) in order to avoid delayed expansion, because this is not enabled in either new cmd
instance. To output the resulting values, I make use of the fact that either of the for /F
loops are running in cmd
context rather than in batch
context, where set /A
outputs the result to STDOUT
. set /A
does not terminate its output with a line-break, so I use set /P
to append a .
after each but the last item, which in turn does not append a line-break. For the last item I append a line-break using a blank echo
.
Right Side of the Pipe:
The sorting is again accomplished by the sort
command, whose output is parsed by for /F
. Here the previously added value 10000
is subtracted from each component to retrieve the original numbers. For outputting the result to the console, the same technique is used as for the other side of the pipe.
Piped Data:
The data passed over by the pipe looks like this (relying on the example of the question once again):
10003.10006.10004.10002
10003.10006.10005.10001
10003.10006.10005.10010
10003.10006.10005.10011
10003.10006.10005.10012
10003.10006.10005.10013
10003.10006.10005.10002
10003.10006.10007.10001
10003.10006.10007.10010
10003.10006.10007.10011
10003.10006.10007.10002
10003.10006.10007.10003