26

I need to check if a parameter that is passed to a Windows Batch file is a numeric value or not. It would be good for the check to also works for variables.

I found an answer to a similar question, where the findstr command is used with a regular expression.

I did try that solution, but it’s not working like I hoped (at least on Windows 7).

My test scenarios are as follows:

AA  # not a valid number
A1  # not a valid number
1A  # not a valid number

11  # a valid number
ib.
  • 27,830
  • 11
  • 80
  • 100
mhshams
  • 16,384
  • 17
  • 55
  • 65
  • 2
    See http://www.robvanderwoude.com/sourcecode.php?src=isnumber_nt [Direct](http://www.robvanderwoude.com/files/isnumber_nt.txt) – David Ruhmann Jul 11 '13 at 04:40
  • NOTE TO OTHER READERS: This question can and has been interpreted multiple ways. Some answers below are testing for things acceptable to CMD.EXE as numbers. Other answers are testing for some other definition of "number", such as the one given in the original question. Which answer is best depends on one's needs. Choose wisely. :-) – Ben Scott Mar 01 '21 at 15:46

11 Answers11

57
SET "var="&for /f "delims=0123456789" %%i in ("%1") do set var=%%i
if defined var (echo %1 NOT numeric) else (echo %1 numeric)

Replace %1 with %yourvarname% as appropriate

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • 7
    +1 but also enclosing the `"var=%%i"` with double quotes will protect against some poison characters. – foxidrive Jul 12 '13 at 17:28
  • 2
    Not working in Windows 10 anymore as far as I'm concerned. `var` is not defined if I assign `%yourvarname%` a numeric value. Any ideas? – nst1nctz Mar 20 '17 at 01:17
  • 1
    @nst1nctz: Works perfectly happily for me - Please give example(s) of values for which it fails. Note that `var` is designed to be undefined if `%1` is numeric and defined if `%1` is numeric. – Magoo Mar 20 '17 at 01:56
  • You're right, it works when I test it in an isolated batch file. I will comment if I find out why it did not work in my original script -- unless it was just a silly bug on my behalf, in which case I will remain silent :) – nst1nctz Mar 23 '17 at 18:28
  • 2
    One should always question their own code -- I am still in the progress of learning to never trust my own work. +1 – nst1nctz Mar 23 '17 at 18:30
  • Great example , but written non-intuitive for beginners .. var should be something like 'test' and %1 should be %test_var% etc .. imo – Mike Q Mar 12 '20 at 00:22
  • 2
    @MikeQ: Batch is often that way. Consider this a template. First, `%1` is the first argument to a batch procedure, so `call :chknumeric %varname%` would substitute the value of `varname` for `%1` Precede the active line with a label `:chknumeric` & put `goto :eof` on the following line & you have a procedure to return `var`. This routine is targeted at numeric strings & will process barcode numbers for instance. alter `var` to `notnumeric` if you will - but `var` can be checked against "." to test for a single decimal point. Or against a different character-set & the logical name changes again – Magoo Mar 14 '20 at 18:39
  • I had a similar issue where the script above did not run for me on Win10, it just gave me an error message. The solution was to change the extension of my batch file from .bat to .cmd. – code-it Aug 01 '23 at 15:32
16

for ± integers (test also for leading zero):

echo(%~1|findstr "^[-][1-9][0-9]*$ ^[1-9][0-9]*$ ^0$">nul&&echo numeric||echo not numeric
Endoro
  • 37,015
  • 8
  • 50
  • 63
  • 1
    +1, Though you will have problems if a parameter like `"this&that"` is passed. A bit more work can fix that problem ;) – dbenham Jul 11 '13 at 12:45
  • 1
    @dbenham yes. The best is quoting and adding some dots to the Regex. Thanks. – Endoro Jul 11 '13 at 12:57
  • 2
    @Endoro: this command handles poison characters correctly as well: `echo("%~1"|findstr "^[\"][-][1-9][0-9]*[\"]$ ^[\"][1-9][0-9]*[\"]$ ^[\"]0[\"]$">nul&&echo numeric||echo not numeric` – Chaoix Mar 22 '16 at 14:08
9

You could try this. The variable passed is for example var and %var% is equal to 500.

set /a varCheck=%var%
if %varCheck% == %var% (goto :confirmed) else (exit /B)
exit /B

:confirmed
:: You can use %var% here, and it should only be executed if it is numerical!

if %var% is equal to e.g. a3453d, then it would set varCheck to be 0, and because 0 is not equal to a3453d, then it will exit batch processing.

(The exit on line 3 is just in case the if statement decides not to execute for some reason ... XD.)

Mofi
  • 46,139
  • 17
  • 80
  • 143
hornzach
  • 305
  • 2
  • 5
  • 1
    your solution failed in scenario #3. it shows following error and terminates the batch execution. ERROR: "Invalid number. Numeric constants are either decimal (17), hexadecimal (0x11), or octal (021). (echo was unexpected at this time." – mhshams Jul 11 '13 at 03:48
  • 1
    dammit.. I don't know then... I will ask a friend of mine who is an EXPERT at batch files. – hornzach Jul 11 '13 at 04:22
9

The easiest for positive integers should be:

IF 1%1 NEQ +1%1 echo Notnumeric!

If negative numbers (hyphen) are also to be considered, this will work

SET number=%1
if 1%1 EQU +1%1 echo positive number
if %1==-%number:-=% echo negative number

Learned from this article here

Hello
  • 77
  • 1
  • 13
Alim Özdemir
  • 2,396
  • 1
  • 24
  • 35
  • 1
    Good to know, but FYI to others, this only works for INTEGERS. See other answers if you need to support decimal. – Jerren Saunders Jul 12 '19 at 14:23
  • 1
    Oh this is SO COOL, thank you for posting! it's exactly what I needed (for integers). Very clean and concise. – Drac Jun 11 '20 at 03:16
  • 1
    FYI, this fails for a few corner cases that are acceptable to CMD as numbers: Octal (`020`) and hex (`0x10`). Positive zero (`+0`). Repeated negation (CMD treats `--5` as 5). This may be unimportant to one's needs, but is worth mentioning. Overall it works pretty well, and for little code. – Ben Scott Mar 01 '21 at 15:19
  • This fails on null parameters. When passing two params into `test.bat 2 bar`, `%1` is numeric, `%2` is not numeric, and `%3` is numeric. – Skull Kid Apr 18 '23 at 18:39
6

@hornzach - You were so close and with a much simpler answer than the rest.

To hide the error message in (win 7 at least) redirect to the standard error output (2) to nul (a special file, that quietly discards the output "bit-bucket")

set /a varCheck = %var% 2>nul

Then the rest of your answer works for the 4 test cases.

Full Answer With Test Cases:

call :CheckNumeric AA  "#NOT A VALID NUMBER"
call :CheckNumeric A1  "#NOT A VALID NUMBER"
call :CheckNumeric 1A  "#NOT A VALID NUMBER"

call :CheckNumeric 11  "#A VALID NUMBER"

call :CheckNumeric 1.23456789012345678901234567890.123456  "#NOT A VALID NUMBER"
goto :EOF

:CheckNumeric
@ECHO.

@ECHO Test %1
set /a num=%1 2>nul

if {%num%}=={%1} (
    @ECHO %1 #A VALID NUMBER, Expected %2
    goto :EOF
)

:INVALID
    @ECHO %1 #NOT A VALID NUMBER, Expected %2

Outputs:

Test AA
AA #NOT A VALID NUMBER, Expected "#NOT A VALID NUMBER"

Test A1
A1 #NOT A VALID NUMBER, Expected "#NOT A VALID NUMBER"

Test 1A
1A #NOT A VALID NUMBER, Expected "#NOT A VALID NUMBER"

Test 11
11 #A VALID NUMBER, Expected "#A VALID NUMBER"

Test 1.23456789012345678901234567890.123456
1.23456789012345678901234567890.123456 #NOT A VALID NUMBER, Expected "#NOT A VALID NUMBER"
Andrew Dennison
  • 1,069
  • 11
  • 9
  • 3
    This code produces the wrong result for all numbers with 1 or more leading zeros like 05 or 009 as Windows command processor converts the string to a 32-bit signed integer with C function [strtol](http://www.cplusplus.com/reference/cstdlib/strtol/) with function parameter `base` having value `0` (automatic base). Therefore the string comparisons for my two examples are `{5}=={05}` (leading zero removed) and `{}=={009}`. The variable `num` is still undefined for `009` (or keeps its current value in case of being already defined) because `009` is an invalid octal number. – Mofi May 14 '16 at 15:50
  • You can test for leasing 0's e.g. if "%SIZE:~0,1%"=="0" (echo ERROR: %SIZE% is not a valid number & pause & goto :BEGIN) – SSi May 02 '18 at 10:11
  • Good point @Mofi: +1... but no required in the use cases: just decimal numbers (assumed) – 0zkr PM Jul 18 '18 at 16:38
  • 1
    @Cestarian - It depends on the fact that `SET /A` causes CMD.EXE to evaluate an arithmetic expression. It evaluates the original variable `%var%` in such an expression, and stores the result in a second variable `%varCheck%`, and then compares the two variables. If they differ, CMD evaluated it to a different value, which typically means the original value was non-numeric. For example, if you ask CMD for the numeric value of the string `"example"`, CMD will return `0` (zero). Since `"example"` and `0` are not the same value, we can assume a non-numeric value was given. – Ben Scott Mar 01 '21 at 15:54
2

Does the same thing as above. Have problems with special characters. However, the solution is of a different approach.

@echo off
cls
setlocal enabledelayedexpansion

if "%1"=="" (goto:eof) else (set _VAR2CHECK=%1)

for /l %%a in (0,1,9) do (
   if defined _VAR2CHECK (set "_VAR2CHECK=!_VAR2CHECK:%%a=!") else (goto :end)
)

:end
if defined _VAR2CHECK (echo %1 #NOT A VALID NUMBER) else (echo %1 #A VALID NUMBER)

set "_VAR2CHECK="
endlocal

Test scenarions:

C:\>ISNUM 1A
1A  #NOT A VALID NUMBER

C:\>ISNUM 11
11  #A VALID NUMBER
Dharma Leonardi
  • 101
  • 2
  • 3
1

Just try to divide per 1. But it doesn't work with numbers out of Z (non relative integer or decimal).

set var=29
set /a number=%var% >nul 2>&1
set /a number=%number% / 1 >nul 2>&1
if "%var%" == "%number%" (echo numeric) else (echo NOT numeric)
Celes
  • 27
  • 1
  • 5
0

I use this function instead, it seems to work for me without any issues...

The Script (mytestscript.bat)

REM == Script variables =============================================
SET "NUMCODE=%1"
SET "NAME=%2"

REM == Main script ==================================================
CALL :Validate "NUMCODE"
IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL%
CALL :Validate "NAME"
IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL%

ECHO Validation Complete and all variables passed validation.

REM == Functions ====================================================
:IsNumeric [string-value] [return-val]
    SET "stringVal=%~1"
    SET /A numericVal=%stringVal% > nul 2> nul
    IF "%stringVal%"=="%numericVal%" (SET "%~2=1") ELSE (SET "%~2=0")
    EXIT /B 0

:Validate
    SET PASSEDVALIDATION=0

    ECHO Validating %~1...

    IF "%~1"=="NUMCODE" (
        ECHO - Value: %NUMCODE%
        IF NOT "%NUMCODE%"=="" SET PASSEDVALIDATION=1
        IF "!PASSEDVALIDATION!"=="1" (
            CALL :IsNumeric %NUMCODE% RETVAL
            SET PASSEDVALIDATION=!RETVAL!
        )
        IF "!PASSEDVALIDATION!"=="1" (
            IF NOT %NUMCODE% GEQ 1 SET PASSEDVALIDATION=0
        )
        IF "!PASSEDVALIDATION!"=="1" (
            IF NOT %NUMCODE% LEQ 526 SET PASSEDVALIDATION=0
        )
        IF "!PASSEDVALIDATION!"=="0" (
            ECHO - The first parameter is invalid, it can not be blank.
            ECHO - Valid value is a number from 1 to 526.
            ECHO - Leading zeros are not valid.
        )
    )

    IF "%~1"=="NAME" (
        ECHO - Value: %NAME%
        IF NOT "%NAME%"=="" SET PASSEDVALIDATION=1
        IF "!PASSEDVALIDATION!"=="0" (
            ECHO - The second parameter is invalid, it can not be blank.
        )
    )

    IF "!PASSEDVALIDATION!"=="0" (
        ECHO - Failed validation.
        EXIT /B 1
    ) ELSE (
        ECHO - Passed validation.
    )
    EXIT /B 0

Usage Examples:

C:\mytestscript.bat 10 MrTest
Validating NUMCODE...
- Value: 10
- Passed validation.

Validating NAME...
- Value: MrTest
- Passed validation.

C:\mytestscript.bat 600
Validating NUMCODE...
- Value: 600
- The first parameter is invalid, it can not be blank.
- Valid value is a number from 1 to 526.
- Leading zeros are not valid.
- Failed validation.

C:\mytestscript.bat 10
Validating NUMCODE...
- Value: 10
- Passed validation.

Validating NAME...
- Value: 
- The second parameter is invalid, it can not be blank.
- Failed validation.
Arvo Bowen
  • 4,524
  • 6
  • 51
  • 109
0

I use a more low tech approach. It only works with integers and supports negative values.

set "XVALUE=%~1"
set /A XVALUE=XVALUE
if "%XVALUE%" NEQ "%~1" goto :invalid_value

The first line gets the command line argument and drops it into XVALUE. Using the "quotes" prevents issues with various special characters.

The second line looks mysterious but takes advantage of that when there is a text string on the right hand side of the equals sign for SET /A that it's interpreted as an environment variable containing a numeric value. The command processor parses the presumed numeric value without generating any error messages nor setting ERRORLEVEL. Doing it this way always results in XVALUE being converted into a valid numeric value regardless of whatever was passed to us.

The third line is optional and is only needed if you want to be strict about that the argument is a numeric value in the range -2147483648 to 2147483647. If you don't use the if test then

  • You get support for octal and hexadecimal numbers by prefixing them with 0 or 0x.
  • If someone uses a very small or large number such as -9999999999999 or 9999999999999 then XVALUE will be set to the minimum or maximum allowed values which are -2147483648 and 2147483647.
  • If someone uses garbage such as the word "hello" then XVALUE is set to 0. If it's something like 123x456 then the parser stops at the "x" and XVALUE is set to 123.
user3347790
  • 123
  • 2
0

if errorlevel accepts only numeric values which can be used for a checks:

set test_var=001
( 
  (if errorlevel %test_var% break ) 2>nul
)&&(
  echo %test_var% is numeric
)||(
  echo %test_var% is NOT numeric
)

set test_var=001X
( 
  (if errorlevel %test_var% break ) 2>nul
)&&(
  echo %test_var% is numeric
)||(
  echo %test_var% is NOT numeric
)

the first check will pass, the second not. Though the script above would not handle unary + - if you want to handle this case too check - isInteger.bat

npocmaka
  • 55,367
  • 18
  • 148
  • 187
0

I know that this is a quite old thread, but I ran into that problem, too. Some of the proposals given up to this point can (for example) not handle a "&" entered. And I wanted to have a "one-line" solution (no CALL etc.) that is "rock solid" regarding this kind of "poison" characters entered as (part of) keyboard input. My proposal takes a "whitelist"/"cinderella"-approach, checks the variable in question (varinput) digit by digit, simply picks out the "good" ones and concatenates them to "varcleaned".

set varcleaned=&& FOR /L %%i IN (0,1,10) DO (FOR %%j IN (A B C D 0 1 2 3 4) DO (IF "!varinput:~%%i,1!" EQU "%%j" (SET varcleaned=!varcleaned!%%j)))

I have tested it against the most common "poison" characters - and it works. In the example given the whitelist is A to D and 0 to 4 and there are 11 rounds (meaning it does its job for varinput < 12 digits). So, if you would like to have "a numeric" value as varcleaned, simply change the whitelist accordingly. Once you have "cleaned" the variable, you could proceed with the other solutions mentioned above like set /a varinput = %varcleaned% 2>nul. For performance reasons I would keep the number of walkthroughs and the whitelist as small as possible.

Fedor
  • 17,146
  • 13
  • 40
  • 131
Sven
  • 1