With a small formula, you can change the range of the value of random (0 to 32768) to a smaller value. By making that calculation a subroutine, you can easily call it multiple times.
Using setlocal you prevent pollution of your environment. The script below fills the variable serial
with a random serial number consisting of 5 numbers between 1000 and 9999.
Version 1:
@echo off
setlocal
:: Generate 5 random numbers of 4 digits
call :random code1
call :random code2
call :random code3
call :random code4
call :random code5
:: Combine them and show the output.
set serial=%code1%-%code2%-%code3%-%code4%-%code5%
echo %serial%
pause
:: Clear all variables, except %serial%
endlocal & set serial=%serial%
goto :eof
:random
:: Version 1: Generates a random number between 1000 and 9999
setlocal
set /a nr=%random%*8999/32767+1000
endlocal & set %1=%nr%
goto :eof
Version 2:
Since :random is a nice separate subroutine, you can easily change it if you need. For instance, if 1000 to 9999 isn't good enough, you can get the range of 0000 to 9999 and left-pad the generated numbers with zeroes by replacing the subroutine with:
:random
:: Version 2: Generates a random number between 0000 and 9999
setlocal
set /a nr=%random%*9999/32767
set nr=0000%nr%
set nr=%nr:~-4%
endlocal & set %1=%nr%
A breakdown of the code.
setlocal
starts a new local environment. Environment variables are copied into this new environment, but if you change add or remove them, that doesn't affect the environment variables outside of this 'local' scope. See also endlocal.
::
as rem
used for comments
:random
is a label. Identifiers starting with a colon indicate a label. Labels can be used for control flow of the program. The code after this label I call a subroutine. You can jump to a label to execute the subroutine (call) and return from it (goto :eof
) to continue normal execution. It's as if you are calling a separate batch file, only it is embedded in the same file.
call
calls a batch file or subroutine. By specifying a label you jump to another part of the batch file, but unlike goto
, call
allows you to jump back to the calling position.
goto :eof
jumps to the end of the script. If you called a label using call
, this command jumps back to the place of the call and continue execution from there. So it's like returning from a function.
- code1 to code5. I specify the name of the variable in which I want to have the result of the subroutine. That way, I can call it five times to fill five different variables.
endlocal
ends the local scope started with startlocal
.
endlocal & set serial=%serial%
. This is a trick. The local scope is ended, but before it is ended (by executing the line), the command interpreter interprets the entire line, expanding variables. This allows you to set a variable in the outer (or global) scope to a value that was created in the inner scope. I basically use this to specify a return value from the subroutine, and to return the variable serial
from the script.
endlocal & set %1=%nr%
as used in the subroutine. This sets the variable of which the name was specified in the first parameter of the call. So %1
expands to code1
, code2
, etc. This way, the subroutine can set any variable without needing to know which one it is setting.
set /a
sets a variable but allows simple arithmetic formulas (calculations). This way you can calculate a value between 1000 and 9999 (version 1) or 0 and 9999 (version 2).
- In version 2, I pad the value with zeroes if it is shorter. This is done in three steps. First generate the number, then add zeroes in front of it, and lastly, grab the last four characters, using the notation
%nr:~-4%
.
And if all that is too complex for you, you can just copy the formula itself and skip all the rest:
Version 3:
@echo off
set /a code1=%random%*9999/32767
set code1=0000%code1%
set /a code2=%random%*9999/32767
set code2=0000%code2%
set /a code3=%random%*9999/32767
set code3=0000%code3%
set /a code4=%random%*9999/32767
set code4=0000%code4%
set /a code5=%random%*9999/32767
set code5=0000%code5%
set serial=%code1:~-4%-%code2:~-4%-%code3:~-4%-%code4:~-4%-%code5:~-4%
echo %serial%
pause
Version 4:
Very very very simple version.
Jahwi suggested using the modulo operation to limit the number, so using set /a nr=%random%%%10000
would give you a number between 0 and 9999. However, the division isn't really even. Since you get a random number between 0 and 32767, doing just this modulo operation will result in numbers between 0 and 2767 occurring more often than numbers between 2768 and 9999.
If this doesn't bother you, you can use this method, or just simply truncate the value on 4 digits, which essentially has the same effect. The code below just truncates the random number and makes sure they are left padded with zeroes until a length of 4. This is about as short as it gets, but keep in mind that these numbers are less 'pure' and balanced than the ones in versions 1 to 3.
@echo off
set code1=0000%random%
set code2=0000%random%
set code3=0000%random%
set code4=0000%random%
set code5=0000%random%
set serial=%code1:~-4%-%code2:~-4%-%code3:~-4%-%code4:~-4%-%code5:~-4%
echo %serial%
pause