87} How can I create a four-digit random string?
For an instructive example of a CMD-commands-only script creating
random strings see "
MAKEPASS.CMD Make
a randomized password" included in the
tscmd.zip
package.
There is a inbuilt random generator as given by the XP Command-line
reference - Concepts - Command shell overview: The variable
%RANDOM%
a random in a script will be a decimal number between 0 and 32767.
@echo off & setlocal enableextensions
set /a rand_=%random%
%% 10000
set rand_=0000%rand_%
echo %rand_:~-4%
endlocal & goto :EOF
The output might be e.g.
C:\_D\TEST>cmdfaq
rand_=4823
The
%%
is the remainder (modulo) operator
A catch is present, however. If the output is e.g.
rand_=0968
a prefix of
0 indicates an octal number if used in calculations.
Thus as the above would be an invalid octal number because octal
numbers cannot have the digits 8 or 9. To demonstrate
@echo off & setlocal enableextensions
set /a x=
0968
endlocal & goto :EOF
The output would be
C:\_D\TEST>cmdfaq
Invalid number. Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Thus, if it is about numbers to be used in calculations, obviously do
not pad leading zeros into the variable.
A Visual Basic Script (VBScript) aided command line script solution:
@echo off & setlocal enableextensions
::
:: Build a Visual Basic Script and run it with Microsoft Windows Script Host
set skip=
findstr "'%skip%VBS" "%~f0" > "%temp%\tmp$$$.vbs"
cscript //nologo "%temp%\tmp$$$.vbs">"%temp%\tmp$$$.cmd"
::
:: Call the command line script which the script host built
call "%temp%\tmp$$$.cmd"
::
:: Display the result
echo rand_=%rand_%
::
:: Clean up
for %%f in ("%temp%\tmp$$$.vbs" "%temp%\tmp$$$.cmd") do (
if exist %%f del %%f)
endlocal & goto :EOF
'
Randomize 'VBS
MyRandom = Right("0000" & Int(10000*Rnd) , 4) 'VBS
WScript.StdOut.WriteLine "@set rand_=" & MyRandom 'VBS
The output might be e.g.
C:\_M>c:\_d\test\cmdfaq
rand_=7674
To generate a five digit random number between 10000 and 99999
@echo off & setlocal enableextensions
::
:: Build a Visual Basic Script
set skip=
set temp_=%temp%
if defined mytemp if exist "%mytemp%\" set temp_=%mytemp%
set vbs_=%temp_%\tmp$$$.vbs
>"%vbs_%" findstr "'%skip%VBS" "%~f0"
::
:: Run the script with Microsoft Windows Script Host Version 5.6
:: to generate a five digit random number between 10000 and 99999
for /f "tokens=*" %%a in ('
cscript //nologo "%vbs_%" 10000 99999') do (
set random_=%%a)
echo random_=%random_%
::
:: Clean up
for %%f in ("%vbs_%") do if exist %%f del %%f
endlocal & goto :EOF
'
'The Visual Basic Script
Randomize 'VBS
Set arg = WScript.Arguments 'VBS
Wscript.Echo RandomFn(arg(0), arg(1)) 'VBS
'
Function RandomFn (low, high) 'VBS
RandomFn = Int (low + (high - low + 1) * Rnd) 'VBS
End Function 'VBS
The output might be e.g.
C:\_M>c:\_d\test\cmdfaq
random_=72010
One of the options is to use G(nu)AWK. The string is between 0000
and 9999. Leading zeros are added by the solution as needed.
@echo off & setlocal enableextensions
::
:: Create a random number between 0-9999
gawk 'BEGIN{srand();printf
^
"@set rand_=%%04d\n",int(10000*rand())}'
^
>"%temp%\tmp$$$.cmd"
for %%c in (call del) do %%c "%temp%\tmp$$$.cmd"
::
:: Display the result
echo rand_=%rand_%
endlocal & goto :EOF
The output might be e.g.
C:\_D\TEST>cmdfaq
rand_=0857
or
@echo off & setlocal enableextensions
rem The same with GnuWin32 gawk (let's call it unxgawk)
::
set temp_=%temp%
if defined mytemp if exist "%mytemp%\" set temp_=%mytemp%
::
:: Build a gawk source
set awksrc=%temp_%\tmp$$$.awk
> "%awksrc%" echo BEGIN{
>> "%awksrc%" echo srand()
>> "%awksrc%" echo printf "%%04d\n",int(10000*rand())
>> "%awksrc%" echo }
::
for /f "usebackq" %%a in (`
unxgawk -f %awksrc%`) do set rand_=%%a
for %%f in (%awksrc%) do if exist %%f del %%f
::
:: Display the result
echo rand_=%rand_%
endlocal & goto :EOF
or just
@echo off & setlocal enableextensions
for /f "usebackq" %%a in (`unxgawk "BEGIN{srand();printf \"%%04d\n\",int(10000*rand())}"`) do set rand_=%%a
echo rand_=%rand_%
endlocal & goto :EOF
Incidentally, if one only needs two digits one quick-and-dirty
alternative is to take the current milliseconds:
%time:~9,2%
Consider a slightly different task. Get random numbers from 1 to 52
without any repeats. Like shuffling a deck of cards numbered 1-52.
Using VBS-aided scripting and the shuffle algorithm to avoid any
repeats we get:
@echo off & setlocal enableextensions enabledelayedexpansion
::
:: Set the number of random numbers to be shuffled
:: Typically 52 would be a deck of cards
set max_=52
::
:: Build a Visual Basic Script
set vbs_=%mytemp%\tmp$$$.vbs
findstr "'%skip%VBS" "%~f0" > %vbs_%
::
:: Run it with Microsoft Windows Script Host Version 5.6
set cmd_=%mytemp%\tmp$$$.cmd
cscript //nologo %vbs_% > %cmd_%
::
:: Call the command line script which the script host built
call %cmd_%
::
:: Display the results
for /l %%i in (1,1,%max_%) do echo rand[%%i] = !rand[%%i]!
::
:: Clean up
for %%f in ("%vbs_%" "%cmd_%") do if exist %%f del %%f
endlocal & goto :EOF
'
'.......................................................
'The Visual Basic Script
'
Dim maxItems, i, j, k, rand(1000) 'VBS
Set WshShell = WScript.CreateObject("WScript.shell") 'VBS
maxItems=WshShell.ExpandEnvironmentStrings("%max_%") 'VBS
Randomize 'VBS
For i = 1 to MaxItems 'VBS
rand(i) = i 'VBS
Next 'VBS
For i = 1 to MaxItems 'VBS
j = 1 + Int(MaxItems*rnd) 'VBS
k = rand(i) 'VBS
rand(i) = rand(j) 'VBS
rand(j) = k 'VBS
Next 'VBS
For i = 1 to MaxItems 'VBS
WScript.Echo "@set rand[" & i & "]=" & rand(i) 'VBS
Next 'VBS
The output would be e.g.
C:\_D\TEST>cmdfaq
rand[1] = 3
rand[2] = 6
:
rand[50] = 36
rand[51] = 26
rand[52] = 40