1

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 :)

6
  • Yes, it is possible. But what have you tried so far that isn't working? Commented Jul 7, 2016 at 13:38
  • I tried with the SET /P command, but the user can enter letters and I don't want that... Commented Jul 7, 2016 at 13:40
  • You should update your question with the code that you've tried so far. Input from the console is inherently string based, so you can expect to get anything from a user. You will have to validate it yourself. Commented Jul 7, 2016 at 13:42
  • How can I validate it ? Do you have suggestions Commented Jul 7, 2016 at 13:45
  • 1
    There's only 12 months in a year BTW :-p Commented Jul 7, 2016 at 13:54

5 Answers 5

5
@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
)

?

Sign up to request clarification or add additional context in comments.

6 Comments

Shouldn't that be 1 - 12 for month?
@ManoDestra the op says between 1-31
Didn't realize that there were 31 months in the year. OP must be wrong :-p Good solution.
@ThomasJomphe fails if user enters something like 2xy (after your edit - npocmaka's original code covered that)
I'm afraid this fails if the user enters something like 08 or 09...
|
3

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%

1 Comment

Allowing a preceding 0 for numbers from 2 to 9 optionally would appear more comfortable to me, but great approach anyway!
1

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.).

Comments

1

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
)

Comments

0

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 ←— key; since we need a two-digit numeric value, 2 is the value of choice here;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.