Generating a random number from 0-9 in a Windows batch file - windows

I'm trying to write a Windows batch file that will generate a random number from 0 to 9 and then load a different map list in our game server based on the random number.
I have tried to modify a similar file that was on this forum for generating random characters, but when I reduce the maxchars variables to 1 in length.
I sometimes get #echo is off as a response and sometimes get a number.
Here's what I have:
#echo off & setlocal EnableDelayedExpansion
REM Random.bat
REM
REM Change these values to whatever you want, or change the code to take them
REM as command-line arguments. You must set CHARS_LEN to the string length
REM of the string in the CHARS variable.
REM
REM This script generates a string of these characters at least
REM MIN_CHARS_IN_LINE chars long and at most MAX_CHARS_IN_LINE chars long.
SET CHARS=0123456789
SET /A CHARS_LEN=10 + 10 + 10
SET /A MIN_CHARS_IN_LINE=1
SET /A MAX_CHARS_IN_LINE=2
REM Pick a random line length and output a random character until we reach that
REM length.
call:rand %MIN_CHARS_IN_LINE% %MAX_CHARS_IN_LINE%
SET /A LINE_LENGTH=%RAND_NUM%
SET LINE=
for /L %%a in (1 1 %LINE_LENGTH%) do (
call:rand 1 %CHARS_LEN%
SET /A CHAR_INDEX=!RAND_NUM! - 1
CALL SET EXTRACTED_CHAR=%%CHARS:~!CHAR_INDEX!,1%%
SET LINE=!LINE!!EXTRACTED_CHAR!
)
echo !LINE!
goto:EOF
REM The script ends at the above goto:EOF. The following are functions.
REM rand()
REM Input: %1 is min, %2 is max.
REM Output: RAND_NUM is set to a random number from min through max.
:rand
SET /A RAND_NUM=%RANDOM% * (%2 - %1 + 1) / 32768 + %1
goto:EOF
:eof
Once I can get this reliably choosing characters I just need to add a selection process to the end which will call the server with a different command line for each map list.

The LastStar007 method works great for values between 0 and 9. For a more generic solution that returns a pseudo random number between 0 and n, simply use SET /A to get %random% modulo (n+1).
For example, to get a random number between 0 and 9 on the command line, use
set /a "rand=%random% % 10"
If used in a batch file then the modulo operator must be doubled
set /a "rand=%random% %% 10"

Use the random string in SET and then lop off everything but the last character.
SET RAND=%RANDOM:~-1%

If your problem still persists, try the following. It generates a number between a and b. Tweak it to your needs:
#echo off
color 02
echo enter value of A
set /p a=
echo.
echo enter value of B
set /p b=
:main
set no=%random%
if %no% GEQ %a% goto sub
if not %no% GEQ %a% goto main
:sub
if %no% LEQ %b% goto end
if not %no% LEQ %b% goto main
:end
echo %no%
goto main

Related

Batch for loop find string in variable

I want to find the string A in the variable Code=AAABASDG
and count each time 1 up if "A" was found so the result should be that it outputs 4 because in Code variable there are 4 A's
Example Code :
#echo off
set /A C=0
set Code=AAABASDG
for %%i in (%Code%) do IF "%%i"=="A" set /A C=%C%+1
echo %C%
pause
You could get the length of original string A, then delete the "A" letters from the string and get the length of the result, to finally subtract both lengths.
To easily get the length of the string, you could store it in a file and then ask for the %%~Z size of the file. Here it is:
#echo off
setlocal
set "Code=AAABASDG"
> before.txt echo %code%
> after.txt echo %code:A=%
for %%b in (before.txt) do for %%a in (after.txt) do set /A "count=%%~Zb-%%~Za"
echo %count%
The only drawback of this method is that it is not case-aware: both upcase and lowcase letters are delete in the replacement operation
#echo off
set /A C=0
set "Code=AAABASDG"
:loop
if defined code (
if "%code:~-1%"=="A" set /a C+=1
set "code=%code:~0,-1%"
goto loop
)
echo %C%
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier.
Substrings in batch are obtained from %var:~m,n% where ,n is optional; m is count-of-chars-from-beginning-of-string, from end if negative. ,n positive = max length to return; negative = end-position in chars from end; missing=return all after m
Here's a quick example which gets help from PowerShell:
#Echo Off
SetLocal EnableExtensions
Set "Code=AAABASDG"
For /F %%G In ('%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe
-NoProfile "[RegEx]::Matches('%Code%','A').Count"') Do Set "C=%%G"
Echo(%C%
Pause

How to request integer input from user in batch file

I want to create a batch file on Windows that can let the user enter only a number between 1-31... I could use this number later in the batch file... It is possible ?
I tried this
set /P "month=Enter the month of the year : "
findstr /i %month% %file% | sort /+24
Thanks :)
#echo off
:try_again
set /P "month=Enter the month of the year : "
echo %month%|findstr /r "[^0-9]" && (
echo enter a number
goto :try_again
)
::clears the leading zeroes.
cmd /c exit /b %month%
set /a month=%errorlevel%
if %month% gtr 31 (
echo enter a number between 1 and 31
goto :try_again
)
if %month% lss 1 (
echo enter a number between 1 and 31
goto :try_again
)
?
Well, these two options are entirely different:
Let the user enter anything; then, check if the input is a number between 1 and 12 and retry the input if it is not.
Let the user just enter a number between 1 and 12.
The Batch file below implement the second method:
#echo off
setlocal EnableDelayedExpansion
echo Precede numbers 1 and 2 by a zero
set /P "=Enter a month: " < NUL
choice /C 0123456789 > NUL
set /A "number=%errorlevel%-1"
if %number% gtr 1 echo %number% & goto continue
set /P "=%number%" < NUL
if %number% equ 0 (
choice /C 12 > NUL
set "digit2=!errorlevel!"
) else (
choice /C 012 > NUL
set /A "digit2=!errorlevel!-1"
)
echo %digit2%
set /A "number=number*10+digit2"
:continue
echo/
echo Number read: %number%
A very simple but efficient method I use when I need a non-zero numeric input is the following code (note that this verifies the user entry afterwards):
:RETRY_RESET
rem /* Since zero is considered as invalid, preset variable to `0` to
rem not keep the former value in case the user just presses ENTER;
rem you could also define a non-zero default value here optionally: */
set /A NUMBER=0
:RETRY_REUSE
rem // Display prompt now:
set /P NUMBER="Please enter a positive number: "
rem /* Convert entry to a numeric value; everything up to the first
rem numeral is converted to a numeric value, except leading SPACEs
rem or TABs are ignored and signs `+` and `-` are recognised: */
set /A NUMBER+=0
rem /* Caution: numbers with leading `0` are converted to octal ones!
rem since `8` and `9` are not valid octal numerals, entries with
rem such figures and leading zeros are converted to `0`! */
rem // Verify entry:
if %NUMBER% EQU 0 goto :RETRY_RESET
rem // Do something with `%NUMBER%` at this point...
rem /* Afterwards you can jump to `:RETRY_RESET` to enter another number;
rem alternatively, jump to `:RETRY_REUSE` to maintain the former entry
rem in case the user just presses ENTER... */
This will not fail for any entry you can think of because the variable NUMBER holding the value is never expanded before it is converted to a true number by set /A NUMBER+=0.
The script recognises + and - signs correctly. Leading white-spaces are ignored. Besides all those, everything up to the first non-numeric figure is converted to a number; so for instance, an entry like SPACE+15.75k is converted to 15 as the . is not a numeral.
The disadvantage of this approach is that leading zeros may lead to unexpected results as set /A interpretes numbers with such as octal ones; so for instance, 012 is converted to (decimal) 10, and 08 and 09 are converted to 0 as 8 and 9 are not valid octal digits.
A good point though could be the fact that hexadecimal numbers are recognised correctly in case they are prefixed with 0x; for example, 0x18 is converted to 24; 0xAS becomes 10 (as S is not hex.).
A safe and simple manner for performing this task is the use of the Set /A command in conjunction with the || conditional operator and a :label to return to for when invalid input is entered.
A number of tests can be performed on the input value using set /a without expanding the variables content in a manner that leaves your code vulnerable to code injection.
An example:
#Echo off
Call:ValidNum $RV 31
Call:ValidNum "" "" 5
Set $
Goto:Eof
:ValidNum [returnvar] [max] [min]
SETLOCAL
Set "sign=-1"
:VNumIn
%= ensure nul value =%
Set "input="
%= define max value =%
2> nul Set /a "max=%~2" || Set "max=2147483647"
%= define min value =%
2> nul Set /a "min=%~3" || Set "min=1"
Set /p "input=Enter a number GEQ %min% LEQ %max%: "
%= Input Testing. input +/- , input > min , input < max , Hex/Octal for comparison =%
2>nul Set /a "1/(sign-(input>>31))","max/(input/min)","1/(max/input)","HexOct=input" || Goto:VNumIn
%= compare assignments to block hex, octal and leading 0's =%
If not "%Input%"=="%HexOct%" Goto:VNumIn
( %= return value in $Num if no arg 1, else return in Arg1 =%
ENDLOCAL & Set "%~1=%input%" 2> nul || Set "$Num=%input%"
Goto:Eof
)
The following script is sort of a mixture of both restricting characters/key during entry and verifying characters/value after entry. The code is quite complex but it is very flexible and also safe. Here is it:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here (`findstr` reg. expr.):
set "WHITE=[0-9]" & rem // (positive list, accepted characters)
set "BLACK=[^`^]" & rem // (negative list, rejected characters)
set "LENGTH=2" & rem // (optional limit for length of entry)
rem // resolve length limit:
set /A LENGTH-=1
if %LENGTH% LSS 0 set "LENGTH="
rem // Retrieve back-space character:
for /F %%C in ('echo prompt $H ^| cmd') do set "BS=%%C"
:HOOK
rem // Display prompt:
echo(Please enter something:
set "ENTRY="
:LOOP
rem // Use `xcopy /W` to capture a single key stroke:
set "KEY="
for /F "delims=" %%K in ('2^> nul xcopy /L /W "%~f0" "%~f0"') do (
if not defined KEY set "KEY=%%K"
)
set "KEY=%KEY:~-1%"
rem // Leave loop in case ENTER has been pressed:
if not defined KEY goto :NEXT
rem // Disallow `"` to avoid syntax errors (`if`, no del. exp.):
set "KEY=%KEY:"=%" & rem "
rem // Disallow `=` to avoid syntax errors (`set /P`):
if "%KEY%"=="=" set "KEY="
rem // Disallow ` ` (tabulator):
if "%KEY%"==" " set "KEY="
rem // Optional additional filter (include):
if defined WHITE (
(echo("%KEY%" | > nul findstr /R /C:"%BS%" /C:"%WHITE%") || (
set "KEY="
)
)
rem // Optional additional filter (exclude):
if defined BLACK (
(echo("%KEY%" | > nul findstr /R /C:^"\"%BLACK%\"^") || (
set "KEY="
)
)
rem // In general, display string equals pressed key:
set "DISPLAY=%KEY%"
rem // Avoid space in display text (ignored by `set /P`):
if "%KEY%"==" " set "DISPLAY=_%BS% "
rem // Force to clear preceding character upon back-space:
if "%KEY%"=="%BS%" (
set "DISPLAY=%BS% %BS%"
if defined ENTRY set "ENTRY=%ENTRY:~,-1%"
set "KEY="
)
rem // Ignore any more character if length limit is reached:
set "TEST=%ENTRY%"
if defined LENGTH if defined ENTRY (
call set "TEST=%%ENTRY:~,%LENGTH%%%"
)
if not "%TEST%"=="%ENTRY%" (
set "KEY=" & set "DISPLAY="
)
set "ENTRY=%ENTRY%%KEY%"
rem // Show display text:
< nul set /P ="%DISPLAY%"
goto :LOOP
:NEXT
echo(
rem /* Verify the entry; for instance,
rem check numeric value after removal of leading zeros: */
cmd /C exit %ENTRY%
set /A ENTRY=%ErrorLevel%
set /A ENTRY+=0 & rem // (conversion to true numeric value)
if %ENTRY% LEQ 0 goto :HOOK
if %ENTRY% GTR 12 goto :HOOK
rem // Do something with the entry (display):
echo(You entered this value:
< nul set /P ="%ENTRY%"
echo(
endlocal
exit /B
The core of the script is the xcopy /L /W command which takes a single key stroke (/W) and does no copying (/L). Its output is captured by a for /F loop to get the current key or character. For displaying < nul set /P is used with nothing sent into its prompt but the message text displayed, which is not terminated by a line-break unlike echo. Consult also the comments (rem) in the code.
The script can be configured in the Define constants here block at the top:
variable WHITE defines a positive character set for the findstr command, one of which a character/key must equal; set to an empty string to disable this set; for our situation, [0-9] is suitable as it defines to accept only numeric figures;
variable BLACK defines a negative character set for the findstr command, one of which a character/key must not equal; set to an empty string to disable this list; since there is already WHITE defined, BLACK is not needed; the first character within the brackets [ ] must be a caret ^ so that the given characters are truly rejected; if the sets in WHITE and BLACK overlap, the latter takes precedence;
variable LENGTH defines the greatest length of the entry, so if the given number of characters have been supplied, no more are accepted; you can delete the last character though by the &leftarrow;— key; since we need a two-digit numeric value, 2 is the value of choice here;

windows batch file array extraction counter not being incremented by +=

I am translating a shell script to windows batch. What I need to do is take all except 1,2 and last from command line arguments. join them and send to another program as argv.
#echo off
SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
ECHO %%A
set /a i+=1
IF %i% geq 2 (
set /a c+=1;
set candidates[!c!]=%%A
)
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%
I want the candidates array be argv[3..n-1]
e.g. If I write batch x 2 a b p it should pass a b to that another program
The problem is loop counter is not being incremented by += operator. If I write echo %1% inside FOR I see 0 always
You should not use for %%A in (%*) as it treats %* as filename set. This may cause problems, especially if you can pass * or ? (wildcard match characters in cmd) in parameters - as they will be expanded to all files satisfying pattern. Second, batch does really know nothing about arrays - a[1] and a[2] are just a shorthand notation for humans - they are two distinct variables.
Given the problem Parse command line, take second parameter as count of parameters to concatenate into a variable, here is my take:
#echo off
setlocal
set subject=%1
shift
set exp_count=%1
if not defined exp_count (
echo Count not specified
exit /b 1
)
set /a "verify=%exp_count%"
if %verify% leq 0 (
echo Count not valid /not a positive integer/
exit /b 2
)
set real_count=0
:loop
shift
if "%~1"=="" goto end_params
set /a real_count+=1
if %real_count% leq %exp_count% set "candidates=%candidates%%~1"
goto loop
)
:end_params
if %real_count% lss %exp_count% (
echo Less parameters passed than specified!
exit /b 3
)
echo %subject%
echo %candidates%
Please note I'm not checking if there is a 'hanging' parameter (the last, not being concatenated) but it should be trivial to add that check. I left it out on purpose to make the code more flexible.
I have two answers for your question:
1- The first problem is that in IF %i% ... command the value of i variable not change (although set /a i+=1 command will correctly increment the variable) and the way to solve it is by including setlocal EnableDelayedExpansion command at beginning and enclose i in percents signs this way: IF !i! ... (as said in previous answers). However, you must note that an array variable in Batch is different than a simple variable with same name (they both can exist at same time), so array elements must always be written with subscripts and there is NO way to process an entire array in a single operation. See this topic for further details.
In your program you must transfer the elements of candidates array into a simple variable, that in the example below have the same name (just to state my point):
#echo off
setlocal EnableDelayedExpansion
SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
ECHO %%A
set /a i+=1
IF !i! geq 2 (
set /a c+=1
set candidates[!c!]=%%A
)
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
REM Transfer "candidates" array elements into "candidates" simple variable:
set candidates=
FOR /L %%i IN (1,1,%c%) do (
set candidates=!candidates! !candidates[%%i]!
)
REM Show "candidates" simple variable:
echo %candidates%
Note that in Batch files you may insert commas, semicolons and equal-signs as separators instead spaces in most commands. However, SET /A command have other rules at this respect, so the semicolon must be omitted.
2- Independently of the array management explained above, this is the way I would solve your problem using a list instead of an array:
#echo off
SET subject=%1
shift
set count=%1
set candidates=
set lastArg=
set i=0
:nextArg
shift
if "%1" equ "" goto endArgv
set /a i+=1
set candidates=!candidates! !lastArg!
set lastArg=%1
goto nextArg
:endArgv
SET /a count_actual=i-3, count_expected=count
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%
Antonio
Yes your code will not increment i. Batch variable replacement occurs when a block is parsed, not when it is executed. The entire for block is parsed once, so %i% is replaced with zero before the for block is executed.
To disable that you need to enable delayed expansion and change your variable escape characters from %'s to !'s to have the replacement made at runtime. Then you will see i incremented in the for loop.
#echo off
Setlocal EnableDelayedExpansion
SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
ECHO %%A
set /a i+=1
IF !i! geq 2 (
set /a c+=1
set candidates[!c!]=%%A
)
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%
You will also need to get rid of the ; at the end of the set /a c+=1; line and I'm not sure what you are trying to do on line set candidates[!c!]=%%A as the brackets don't mean anything in batch.
While there are a bunch of answers already listed, I decided to add one more. My approach is to keep the answer as simple as possible for your specific needs. If you have any questions feel free to ask.
This will create the array as you desired [3,...,n-1] without the need for delayed expansion or fancy logic.
#echo off
:: Get the First Two Parameters
set "subject=%1"
shift
set "count=%1"
shift
:: Loop through the rest
set "index=0"
:NextParam
set "param=%1"
shift
set "next=%1"
:: Skip the last parameter
if not defined next goto EndParam
set "candidates[%index%]=%param%"
set /a "index+=1"
goto NextParam
:EndParam
set "count_actual=%index%"
set "count_expected=%count%"
:: Show the Results
echo %count_actual%
echo %count_expected%
echo %subject%
set candidates
Here is an alternate where the candidates are stored in a space delimited string instead of seperate variables. Replace the space between the %candidates% %param% to whatever delimiter you desire.
#echo off
:: Get the First Two Parameters
set "subject=%1"
shift
set "count=%1"
shift
:: Loop through the rest
set "index=0"
:NextParam
set "param=%1"
shift
set "next=%1"
:: Skip the last parameter
if not defined next goto EndParam
set "candidates=%candidates% %param%"
set /a "index+=1"
goto NextParam
:EndParam
set "count_actual=%index%"
set "count_expected=%count%"
:: Show Results
echo %count_actual%
echo %count_expected%
echo %subject%
echo %candidates%

String processing in windows batch files: How to pad value with leading zeros?

in a Windows cmd batch file (.bat), how do i pad a numeric value, so that a given value in the range 0..99 gets transformed to a string in the range "00" to "99". I.e. I'd like to having leading zeros for values lower than 10.
There's a two-stage process you can use:
REM initial setup
SET X=5
REM pad with your desired width - 1 leading zeroes
SET PADDED=0%X%
REM slice off any zeroes you don't need -- BEWARE, this can truncate the value
REM the 2 at the end is the number of desired digits
SET PADDED=%PADDED:~-2%
Now PADDED holds the padded value. If there's any chance that the initial value of X might have more than 2 digits, you need to check that you didn't accidentally truncate it:
REM did we truncate the value by mistake? if so, undo the damage
SET /A VERIFY=1%X% - 1%PADDED%
IF NOT "%VERIFY%"=="0" SET PADDED=%X%
REM finally update the value of X
SET X=%PADDED%
Important note:
This solution creates or overwrites the variables PADDED and VERIFY. Any script that sets the values of variables which are not meant to be persisted after it terminates should be put inside SETLOCAL and ENDLOCAL statements to prevent these changes from being visible from the outside world.
If you are confident that the number of digits in your original number is always <= 2, then
set "x=0%x%"
set "x=%x:~-2%"
If the number may exceed 2 digits, and you want to pad to 2 digits, but not truncate values larger then 99, then
setlocal enableDelayedExpansion
if "%x%" equ "%x:~-2%" (
set "x=0%x%"
set "x=!x:~-2!"
)
Or without delayed expansion, using an intermediate variable
set paddedX=0%x%
if "%x%" equ "%x:~-2%" set "x=%paddedX:~-2%"
The nice thing about the above algorithms is it is trivial to extend the padding to any arbitrary width. For example, to pad to width 10, simply prepend with 9 zeros and preserve the last 10 characters
set "x=000000000%x%"
set "x=%x:~-10%"
TO prevent truncating
set paddedX=000000000%x%
if "%x%" equ "%x:~-10%" set "x=%paddedX:~-10%"
The single line
IF 1%Foo% LSS 100 SET Foo=0%Foo%
will get you what you want for numbers in the range that you specify. It does not change values in the subset 0-9 if they are already single-padded.
Previous answers had explained all the existent methods to pad a value with left zeros; I just want to add a small trick I used to do that in an easier way. What had not been enough mentioned in previous answers is that in most cases, the value that will be padded is incremented inside a loop and that the padded value is just used to display it (or similar tasks, like renames). For example, to show values from 00 to 99:
set x=0
:loop
rem Pad x value, store it in padded
set padded=0%x%
set padded=%padded:~-2%
rem Show padded value
echo %padded%
set /A x+=1
if %x% leq 99 goto loop
If this is the case, the value of the variable may be used for both control the loop and display its padded value with no modification if its limits are appropriately translated. For example, to show values from 00 to 99:
set x=100
:loop
rem Show padded value
echo %x:~-2%
set /A x+=1
if %x% leq 199 goto loop
This method works also with any number of left zeros to pad.
Antonio
OK GUYS i have found a solution, compressing it down as simple as possible.
#echo off
title pad numbers
set num=0
set zero= 000
:loop
#set /a num=%num%+1
if /i %num% GTR 9 set zero= 00
if /i %num% GTR 99 set zero= 0
if /i %num% GTR 999 set zero=
echo %zero%%num%
goto loop
this will display your count up number using 4 digits. but the code can be altered to use 2 digits as shown below.
#echo off
title pad numbers
set num=0
set zero= 0
:loop
#set /a num=%num%+1
if /i %num% GTR 9 set zero=
echo %zero%%num%
goto loop
if you want to set it as a displayable single variable...
#echo off
title pad numbers
set num=0
set zero= 0
:loop
#set /a num=%num%+1
if /i %num% GTR 9 set zero=
set %zero%%num%=number
echo %number%
goto loop
if you want it to count up in seconds...
#echo off
title pad numbers
set num=0
set zero= 0
:loop
#set /a num=%num%+1
if /i %num% GTR 9 set zero=
set %zero%%num%=number
echo %number%
ping localhost -n 2 >nul
goto loop
i hope this was a great help ^^
This example uses a for loop to demonstrate, but the logic is the same even if you were to use it without the loop. Just echo a 0 in front if the number is less than 10.
setlocal enabledelayedexpansion
for /l %%a in (1,1,40) do (
set n=%%a
if !n! lss 10 (
echo 0!n!
) else (
echo !n!
)
)
pause >nul
#echo off
rem .
rem counter example - with and without padding (up to 260 leading 0s which should be enough for most filenames)
rem .
rem we assume values given are valid
rem additional error checking could be done to make sure they are numbers
rem and to ensure that starting is less than ending
rem and that the number of ending digits is not greater than the number of padding digits
rem .
if "%2"=="" (
echo.
echo usage: %~nx0 [starting number] [ending number] [pad]
echo example: %~nx0 0 19 will output numbers 0 to 19 each on a new line
echo example: %~nx0 3 12 8 will output numbers 3 to 12 each on a new line padded to 8 digits
echo.
goto end
)
rem .
setlocal enabledelayedexpansion
if "%3"=="" (
for /l %%x in (%1, 1, %2) do (
echo.%%x
)
) else (
set "mynum="
for /l %%x in (%1, 1, %2) do (
call set "mynum=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000%%x"
call set "mynum=%%mynum:~-%3%%"
call echo.%%mynum%%
)
)
:end
It is much easier:
set build_b=00%your_value%
set padded_value=%build_b:~-2%

Batch File input validation - Make sure user entered an integer

I'm experimenting with a Windows batch file to perform a simple operation which requires the user to enter a non-negative integer. I'm using simple batch-file techniques to get user input:
#ECHO OFF
SET /P UserInput=Please Enter a Number:
The user can enter any text they want here, so I would like to add some routine to make sure what the user entered was a valid number. That is... they entered at least one character, and every character is a number from 0 to 9. I'd like something I can feed the UserInput into. At the end of the routine would be like an if/then that would run different statements based on whether or not it was actually a valid number.
I've experimented with loops and substrings and such, but my knowledge and understanding is still slim... so any help would be appreciated.
I could build an executable, and I know there are nicer ways to do things than batch files, but at least for this task I'm trying to keep it simple by using a batch file.
You're probably not doing this in a DOS batch file. Or at least, support for set /p is unheard of for me in DOS :-)
You could use substrings. In fact I have written a parser for a specific regular language that way once, but it's cumbersome. The easiest way would probably be to assign the contents of %userinput% to another variable, using set /a. If the result comes out as 0 you need to check whether the input itself was 0, otherwise you can conclude it was a non-number:
#echo off
setlocal enableextensions enabledelayedexpansion
set /p UserInput=Enter a number:
set /a Test=UserInput
if !Test! EQU 0 (
if !UserInput! EQU 0 (
echo Number
) else (
echo Not a number
)
) else (
echo Number
)
However, this works only for numbers in the range of Int32. If you just care for any number (possibly floating-point as well) then you need to resort to the loop-based approach of dissecting it.
NOTE: Updated to solve the space issues. However, there is still a problem lurking: Entering 123/5 yields "number", since set /a can evaluate this ...
Thanks all. I was trying to make it harder for myself looking at loops and string manipulation. I used your tips on math evaluation and comparison. Here's what I finally came up with as my concept script:
:Top
#ECHO OFF
ECHO.
ECHO ---------------------------------------
SET /P UserInput=Please Enter a Number:
ECHO.
ECHO UserInput = %UserInput%
ECHO.
SET /A Evaluated=UserInput
ECHO Math-Evaluated UserInput = %Evaluated%
if %Evaluated% EQU %UserInput% (
ECHO Integer
IF %UserInput% GTR 0 ( ECHO Positive )
IF %UserInput% LSS 0 ( ECHO Negative )
IF %UserInput% EQU 0 ( ECHO Zero )
REM - Other Comparison operators for numbers
REM - LEQ - Less Than or Equal To
REM - GEQ - Greater Than or Equal To
REM - NEQ - Not Equal To
) ELSE (
REM - Non-numbers and decimal numbers get kicked out here
ECHO Non-Integer
)
GOTO Top
This method catches all numbers and can detect whether it's positive, negative, or zero. Any decimal or string will be detected as non-integers. The only edge case I've found is a string with spaces. For example, the text "Number 1" will cause the script to crash/close when the user input is evaluated as math. But in my situation, this is fine. I don't want my script to go on with invalid input.
You can also use a quite simple trick:
echo %userinput%|findstr /r /c:"^[0-9][0-9]*$" >nul
if errorlevel 1 (echo not a number) else (echo number)
This uses findstr's regular expression matching capabilities. They aren't very impressive but useful at times.
This is the same idea as that of Johannes..
SET /A sets a numeric value. If the input is not a number, it changes it to 0.
That's what you can exploit here to do your check.
#ECHO OFF
SET /P UserInput=Please Enter a Number:
IF %UserInput% EQU 0 GOTO E_INVALIDINPUT
SET /A UserInputVal="%UserInput%"*1
IF %UserInputVal% GTR 0 ECHO UserInput "%UserInputVal%" is a number
IF %UserInputVal% EQU 0 ECHO UserInput "%UserInputVal%" is not a number
GOTO EOF
:E_INVALIDINPUT
ECHO Invalid user input
:EOF
As an alternative, you could always create a little javascript file and call it from your batchfile. With parseInt() you could force the input to be an integer, or you could roll your own function to test the input.
Writing the javascript is just as fast as the batchfile, but it's much more powerful. No IDE or compiler required; notepad will do. Runs on every windows box, just like your batchfiles. So why not make use of it?
You can even mix batchfiles and javascript. Example:
contents of sleep.js:
var SleepSecs=WScript.Arguments.Item(0);
WScript.Sleep(SleepSecs*1000)
contents of sleep.cmd:
cscript /nologo sleep.js %1
You can now call this from a batchfile to make your script sleep for 10 seconds. Something like that is difficult to do with just a plain batchfile.
sleep 10
As pointed out by ghostdog74, the answers posted by Joey Mar 26 '09 (score 10) and Wouter van Nifterick Mar 26 '09 (score 5) don't work.
The answer posted by Joey Mar 25 '10 (score 2) does work, except that redirection symbols and '&' cause syntax errors.
I think the best and simplest solution is the one posted by Sager Oct 8 '14 (score 0). Unfortunately, it has a typo: ‘"%a"’ should be ‘"%a%"’.
Here's a batch file based on Sager's answer. Redirection symbols and '&' in the input don't cause problems. The only problems I could find were caused by strings containing double quotes.
#echo off & setlocal enableextensions & echo.
set /p input=Enter a string:
SET "x=" & for /f "delims=0123456789" %%i in ("%input%") do set x=%%i
if defined x (echo Non-numeral: "%x:~0,1%") else (echo No non-numerals)
In addition to the remark about the error that occures when spaces are part of the users input. You can use errorlevel errorlevel=9165. It can be used for the spaces in a string or for the error handling of 'no' input.
Kind Regards,
Egbert
You might also like this one - it's short and easy. This one use the multiplication trick to set TestVal. Comparing TestVal against UserInput allows all numeric values to get through including zeroes, only non-numerics will trigger the else statement. You could aslo set ErrorLevel or other variables to indicate a failed entry
#ECHO OFF
SET TestVal=0
SET /P UserInput=Please Enter a Number:
SET /A TestVal="%UserInput%"*1
If %TestVal%==%UserInput% (
ECHO You entered the number %TestVal%
) else ECHO UserInput "%UserInput%" is not a number
GOTO EOF
:EOF
I know this is years old, but just to share my solution.
set /p inp=Int Only :
:: Check for multiple zeros eg : 00000 ::
set ch2=%inp%-0
if %inp% EQU 0 goto :pass
if [%inp%]==[] echo Missing value && goto :eof
if %inp:~0,1%==- echo No negative integers! && goto :eof
set /a chk=%inp%-10>nul
if %chk%==-10 echo Integers only! && goto :eof
:pass
echo You shall pass
:eof
Tested and working on Windows 8.
you can reinvent the wheel and grow a few white hairs doing string validation in batch, or you can use vbscript
strInput = WScript.Arguments.Item(0)
If IsNumeric(strInput) Then
WScript.Echo "1"
Else
WScript.Echo "0"
End If
save it as checkdigit.vbs and in your batch
#echo off
for /F %%A in ('cscript //nologo checkdigit.vbs 100') do (
echo %%A
rem use if to check whether its 1 or 0 and carry on from here
)
You can validate any variable if its number:
SET "var="&for /f "delims=0123456789" %i in ("%a") do set var=%i
if defined var (echo."NIC">nul) else (echo."number")
If you want some sort of a loop and default set up for that particular question, then here's my method for doing this.
Notes on the code within.
#echo off
setlocal EnableDelayedExpansion
set "ans1_Def=2"
:Q1
set /p "ans1=Opt 1 of 1 [Value 1-5 / Default !ans1_Def!]: "
:: If not defined section. This will use the default once the ENTER key has been
:: pressed and then go to :Q2.
if not defined ans1 (
echo/ & echo ENTER hit and the default used. Default is still: !ans1_Def! & echo/
set "ans1=!ans1_Def!" && goto :Q2 )
:: This section will check the validity of the answer. The "^[1-5]$" will work
:: for only numbers between one and five in this example but this can be changed
:: to pretty much suit the majority of cases. This section will also undefine
:: the ans1 variable again so that hitting the ENTER key at the question
:: will work.
echo %ans1%|findstr /r /c:"^[1-5]$" >nul
if errorlevel 1 (
echo/ & echo At errorlevel 1. Wrong format used. Default is still: !ans1_Def! & echo/
set "ans1=" && goto Q1
) else ( echo Correct format has been used. %ans1% is the one. && goto :Q2 )
:Q2
echo/
echo -----------------------------
echo/
echo Now at the next question
echo !ans1!
echo/
pause
exit
Try this:
set /p numeric=enter a number
(
(if errorlevel %numeric% break ) 2>nul
)&&(
echo %numeric% is numeric
)||(
echo %numeric% is NOT numeric
)
Just try this
#echo off
SET constNum=100
:LOOP
Set /p input=Please input a number less than %constNum% :
if "%input%" == "" echo Blank is not allowed & goto LOOP
SET "notNumChar="
for /f "delims=0123456789" %%i in ("%input%") do set notNumChar=%%i
if defined notNumChar (
echo %input% is a string
goto LOOP
) else (
REM Remove leading 0 if it has. eg: 08→8
FOR /F "tokens=* delims=0" %%A IN ("%input%") DO SET inputNum=%%A
)
REM Compare
if defined inputNum (
echo %inputNum%
if %inputNum% equ %constNum% & goto LOOP
if %inputNum% gtr %constNum% & goto LOOP
if %inputNum% lss %constNum% & goto CONTINUE
)
:CONTINUE
:: Your code here
:ASK
SET /P number= Choose a number [1 or 2]:
IF %number% EQU 1 GOTO ONE
IF %number% NEQ 1 (
IF %number% EQU 2 GOTO TWO
IF %number% NEQ 2 (
CLS
ECHO You need to choose a NUMBER: 1 OR 2.
ECHO.
GOTO ASK
)
)
It works fine to me. If he chooses numbers less or greater, strings, floating number etc, he wil receive a message ("You need to choose a NUMBER: 1 OR 2.") and the INPUT will be asked again.
#echo off
setlocal enableextensions enabledelayedexpansion
set /p UserInput=Enter a number:
set /a Test=UserInput
if !Test! EQU 0 (
if !UserInput! EQU 0 (
echo Number
) else (
echo Not a number
)
) else (
echo Number
)
yeaph everthing is great
but you forget about one little thing
0 also is a digit
;(
This is more of a user friendly way.
if %userinput%==0 (
cls
goto (put place here)
)
if %userinput%==1 (
cls
goto (put place here)
)
if %userinput%==2 (
cls
goto (put place here)
)
if %userinput%==3 (
cls
goto (put place here)
)
if %userinput%==4 (
cls
goto (put place here)
)
if %userinput%==5 (
cls
goto (put place here)
)if %userinput%==6 (
cls
goto (put place here)
)if %userinput%==7 (
cls
goto (put place here)
)
if %userinput%==8 (
cls
goto (put place here)
)
if %userinput%==9 (
cls
goto (put place here)
)
This can be used for any type of user input.
for me this is working for all non-zero values ..should i be cautious of some rare cases?
set /a var = %1
if %var% neq 0 echo "it is number"
pause

Resources