128

My OS is Windows Vista. I need to have a ".bat" file where I need to check if user enters any command-line parameter or not. If does then if the parameter equals to -b then I will do something otherwise I will flag "Invalid input". If user does not enter any command-line parameter then I will do something. I have created following .bat file. It works for -b and not-equal to -b cases - but it fails when user does not pass any command-line parameter.

I always get error:

GOTO was unexpected at this time.

Can anyone tell me what am I doing wrong here?


ECHO OFF
CLS
ECHO.

IF [%1]==[/?] GOTO BLANK

IF %1=="-b" GOTO SPECIFIC

IF NOT %1=="-b" GOTO UNKNOWN

:SPECIFIC

ECHO SPECIFIC

GOTO DONE

:BLANK

ECHO No Parameter

GOTO DONE

:UNKNOWN

ECHO Unknown Option

GOTO DONE

:DONE

ECHO Done!
Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
javauser71
  • 4,979
  • 10
  • 27
  • 29

8 Answers8

175

You need to check for the parameter being blank: if "%~1"=="" goto blank

Once you've done that, then do an if/else switch on -b: if "%~1"=="-b" (goto specific) else goto unknown

Surrounding the parameters with quotes makes checking for things like blank/empty/missing parameters easier. "~" ensures double quotes are stripped if they were on the command line argument.

Skip R
  • 383
  • 3
  • 14
afrazier
  • 4,784
  • 2
  • 27
  • 30
  • This works!! Only "else" is not accepted. I get error: 'else' is not recognized as an internal or external command, operable program or batch file. So I added another IF for "not equal to -b" case. Thanks for the quick answer. – javauser71 Feb 10 '11 at 06:29
  • 7
    The ELSE have to be on the same line as the IF, or it has to be directly after a bracket – jeb Feb 10 '11 at 07:30
  • 4
    This does not seem to work for me if %1 contains spaces, which may be the case if it is the full path to an executable. See [Jeremiah Willcock's answer](http://stackoverflow.com/a/4953226/1840078) for a solution that works even for parameters with spaces in their values. – Mark A. Fitzgerald Nov 11 '14 at 02:37
  • it won't be accepted if your argument is a `File`, in that case your should be checking only `exist` or `not exist`. This is why your arguments should be well defined, or simply use powershell or vbScript (if you're in the 80's..) –  Jan 01 '16 at 00:46
  • 1
    This fails for `run.bat "a b"`. `"%1"==""` crashes if the arg has a space. See https://stackoverflow.com/a/46942471 – wisbucky Oct 25 '17 at 21:42
32

Look at http://ss64.com/nt/if.html for an answer; the command is IF [%1]==[] GOTO NO_ARGUMENT or similar.

Jeremiah Willcock
  • 30,161
  • 7
  • 76
  • 78
  • 1
    Not only does this ALSO work! It just works, in contrast to `"%1"==""`. I have to elaborate on that in my own answer. – Tomasz Gandor Nov 09 '16 at 10:49
  • 1
    this will break when %1 is quoted, e.g. `foo.bat "1st parameter" 2nd_param`. See https://stackoverflow.com/questions/2541767/what-is-the-proper-way-to-test-if-variable-is-empty-in-a-batch-file – matt wilkie Jul 18 '17 at 17:20
  • Using `[%1]==[-b]` will not match if arg is quoted. Example `run.bat "-b"`. See https://stackoverflow.com/a/46942471 – wisbucky Oct 25 '17 at 21:44
  • This works for me even when the argument is quoted. e.g. foo.bat "1st parameter" works fine in my testing. The square brackets seem better than IF "%1"=="" – David Pierson Nov 26 '21 at 01:12
28

The short answer - use square brackets:

if [%1]==[] goto :blank

or (when you need to handle quoted args, see the Edit below):

if [%~1]==[] goto :blank

Why? you might ask. Well, just as Jeremiah Willcock mentioned: http://ss64.com/nt/if.html - they use that! OK, but what's wrong with the quotes?

Again, short answer: they are "magical" - sometimes double (double) quotes get converted to a single (double) quote. And they need to match, for a start.

Consider this little script:

@rem argq.bat
@echo off

:loop 
if "%1"=="" goto :done
echo %1
shift
goto :loop

:done
echo Done.

Let's test it:

C:\> argq bla bla
bla
bla
Done.

Seems to work. But now, lets switch to second gear:

C:\> argq "bla bla"
bla""=="" was unexpected at this time.

Boom This didn't evaluate to true, neither did it evaluate to false. The script DIED. If you were supposed to turn off the reactor somewhere down the line, well - tough luck. You now will die like Harry Daghlian.

You may think - OK, the arguments can't contain quotes. If they do, this happens. Wrong Here's some consolation:

C:\> argq ""bla bla""
""bla
bla""
Done.

Oh yeah. Don't worry - sometimes this will work.

Let's try another script:

@rem args.bat
@echo off

:loop 
if [%1]==[] goto :done
echo %1
shift
goto :loop

:done
echo Done.

You can test yourself, that it works OK for the above cases. This is logical - quotes have nothing to do with brackets, so there's no magic here. But what about spicing the args up with brackets?

D:\>args ]bla bla[
]bla
bla[
Done.

D:\>args [bla bla]
[bla
bla]
Done.

No luck there. The brackets just can't choke cmd.exe's parser.

Let's go back to the evil quotes for a moment. The problem was there, when the argument ended with a quote:

D:\>argq "bla1 bla2"
bla2""=="" was unexpected at this time.

What if I pass just:

D:\>argq bla2"
The syntax of the command is incorrect.

The script won't run at all. Same for args.bat:

D:\>args bla2"
The syntax of the command is incorrect.

But what do I get, when the number of "-characters "matches" (i.e. - is even), in such a case:

D:\>args bla2" "bla3
bla2" "bla3
Done.

NICE - I hope you learned something about how .bat files split their command line arguments (HINT: *It's not exactly like in bash). The above argument contains a space. But the quotes are not stripped automatically.

And argq? How does it react to that? Predictably:

D:\>argq bla2" "bla3
"bla3"=="" was unexpected at this time.

So - think before you say: "Know what? Just use quotes. [Because, to me, this looks nicer]".

Edit

Recently, there were comments about this answer - well, sqare brackets "can't handle" passing quoted arguments and treating them just as if they weren't quoted.

The syntax:

if "%~1"=="" (...)

Is not some newly found virtue of the double quotes, but a display of a neat feature of stripping quotes from the argument variable, if the first and last character is a double quote.

This "technology" works just as well with square brackets:

if [%~1]==[] (...)

It was a useful thing to point this out, so I also upvote the new answer.

Finally, double quote fans, does an argument of the form "" exist in your book, or is it blank? Just askin' ;)

Tomasz Gandor
  • 8,235
  • 2
  • 60
  • 55
  • 1
    Square brackets `[%1]==[-b]` will not match if arg is quoted like `run.bat "-b"`. See https://stackoverflow.com/a/46942471 – wisbucky Oct 25 '17 at 21:45
  • Historically note: `[%1]==[-b]` and `"%1"=="-b"` were the same for win 98 and earlier MS/PC-DOS systems batch scripts. Since win 2000/NT introduced syntax `if "%~1"=="-b"` where double quotes have special meaning that is the way you should code scripts as it provides more robust protection. Double quotes escape the meaning of special characters (try & | and % chars in your command line). 99.9% of examples work with double quotes syntax - your example `argq bla2" "bla3` is only case to justify square brackets. Embedded double quotes is a recipe for disaster - just sayin' – Skip R Oct 25 '17 at 23:32
  • @SkipR - that's why in Windows' filesystems, you can't have these special characters in names. I don't have a mathematical proof, but I think that simply NOT everything can be quoted (in the sense of - made verbatim via some escape sequence etc.) in the `cmd` shell. In other systems you can sometimes quote everything, NUL character included. (https://stackoverflow.com/questions/2730732/how-can-i-write-a-null-ascii-character-nul-to-a-file-with-a-windows-batch-scri#2769141) - this question just shows, you need to use some external program. – Tomasz Gandor Oct 27 '17 at 21:59
  • fails with equals sign in args, like `"key=value"`. I got around this for my thing by replacing them in a variable (https://stackoverflow.com/a/51827258/2902367) before I check whether it's empty – Ben Philipp Jul 11 '22 at 13:45
8

In addition to the other answers, which I subscribe, you may consider using the /I switch of the IF command.

... the /I switch, if specified, says to do case insensitive string compares.

it may be of help if you want to give case insensitive flexibility to your users to specify the parameters.

IF /I "%1"=="-b" GOTO SPECIFIC
PA.
  • 28,486
  • 9
  • 71
  • 95
7

You are comparing strings. If an arguments are omitted, %1 expands to a blank so the commands become IF =="-b" GOTO SPECIFIC for example (which is a syntax error). Wrap your strings in quotes (or square brackets).

REM this is ok
IF [%1]==[/?] GOTO BLANK

REM I'd recommend using quotes exclusively
IF "%1"=="-b" GOTO SPECIFIC

IF NOT "%1"=="-b" GOTO UNKNOWN
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • IF [%1]==[/?] is not working but of I do IF [%1]==[] or "%1"=="", then it works. Anyway now I can get going. Thanks for your quick response. – javauser71 Feb 10 '11 at 06:34
6

Actually, all the other answers have flaws. The most reliable way is:

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

Detailed Explanation:

Using "%1"=="-b" will flat out crash if passing argument with spaces and quotes. This is the least reliable method.

IF "%1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "a b"

b""=="-b" was unexpected at this time.

Using [%1]==[-b] is better because it will not crash with spaces and quotes, but it will not match if the argument is surrounded by quotes.

IF [%1]==[-b] (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "-b"

(does not match, and jumps to UNKNOWN instead of SPECIFIC)

Using "%~1"=="-b" is the most reliable. %~1 will strip off surrounding quotes if they exist. So it works with and without quotes, and also with no args.

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat
C:\> run.bat -b
C:\> run.bat "-b"
C:\> run.bat "a b"

(all of the above tests work correctly)
wisbucky
  • 33,218
  • 10
  • 150
  • 101
  • 1
    This is not the end of square brackets, you see: `IF [%~1]==[]` - this works, and it even handles `"-b"`. You just need to be able to think *inside* the box, erm, square [brackets]. – Tomasz Gandor Oct 27 '17 at 21:42
3

I've been struggling recently with the implementation of complex parameter switches in a batch file so here is the result of my research. None of the provided answers are fully safe, examples:

"%1"=="-?" will not match if the parameter is enclosed in quotes (needed for file names etc.) or will crash if the parameter is in quotes and has spaces (again often seen in file names)

@ECHO OFF
SETLOCAL
echo.
echo starting parameter test...
echo.
rem echo First parameter is %1
if "%1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)
C:\>test.bat -?

starting parameter test...

Condition is true, param=-?

C:\>test.bat "-?"

starting parameter test...

Condition is false, param="-?"

Any combination with square brackets [%1]==[-?] or [%~1]==[-?] will fail in case the parameter has spaces within quotes:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if [%~1]==[-?] (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat "long file name"

starting parameter test...

First parameter is "long file name"
file was unexpected at this time.

The proposed safest solution "%~1"=="-?" will crash with a complex parameter that includes text outside the quotes and text with spaces within the quotes:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if "%~1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat -source:"long file name"

starting parameter test...

First parameter is -source:"long file name"
file was unexpected at this time.

The only way to ensure all above scenarios are covered is to use EnableDelayedExpansion and to pass the parameters by reference (not by value) using variables. Then even the most complex scenario will work fine:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
echo.
echo starting parameter test...
echo.
echo First parameter is %1
:: we assign the parameter to a variable to pass by reference with delayed expansion
set "var1=%~1"
echo var1 is !var1!
:: we assign the value to compare with to a second variable to pass by reference with delayed expansion
set "var2=-source:"c:\app images"\image.png"
echo var2 is !var2!
if "!var1!"=="!var2!" (echo Condition is true, param=!var1!) else (echo Condition is false, param=!var1!)
C:\>test.bat -source:"c:\app images"\image.png

starting parameter test...

First parameter is -source:"c:\app images"\image.png
var1 is -source:"c:\app images"\image.png
var2 is -source:"c:\app images"\image.png
Condition is true, param=-source:"c:\app images"\image.png

C:\>test.bat -source:"c:\app images"\image1.png

starting parameter test...

First parameter is -source:"c:\app images"\image1.png
var1 is -source:"c:\app images"\image1.png
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images"\image1.png

C:\>test.bat -source:"c:\app images\image.png"

starting parameter test...

First parameter is -source:"c:\app images\image.png"
var1 is -source:"c:\app images\image.png"
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images\image.png"
D.Barev
  • 31
  • 2
1

This question already has some very good answers, but all answers seem to insist on the usage of a goto.

If you do not want to use a goto in 2023 with Windows 10 which is a slight complication you can simply use parenthesis ( ) after the if statement.

So you can definitely create a batch file like this one:

@echo off

if "%~1"=="full" (
echo hello
echo hello again
)

echo hello always

If you execute this using this command line: if_argument_test.bat full you will see:

hello
hello again
hello always

If you execute it without the full argument you will see this:

hello always

The batch code is just cleaner without the goto.

gil.fernandes
  • 12,978
  • 5
  • 63
  • 76