117

I'm trying to use the following validation logic in a batch file but the "usage" block never executes even when no parameter is supplied to the batch file.

if ("%1"=="") goto usage

@echo This should not execute

@echo Done.
goto :eof

:usage
@echo Usage: %0 <EnvironmentName>
exit 1

What am I doing wrong?

double-beep
  • 5,031
  • 17
  • 33
  • 41
Daniel Fortunov
  • 43,309
  • 26
  • 81
  • 106
  • Possible duplicate of [What is the proper way to test if a parameter is empty in a batch file?](https://stackoverflow.com/questions/2541767/what-is-the-proper-way-to-test-if-a-parameter-is-empty-in-a-batch-file) – double-beep Jan 28 '19 at 17:39
  • 1
    @double-beep - The question here (by daniel-fortunov) was asked first, about a year before the question you refer to was posted. Which is the (possible) duplicate? – Kevin Fegan Sep 04 '20 at 02:22
  • 1
    @KevinFegan because the other question has more views and more answers. – double-beep Sep 04 '20 at 04:25

8 Answers8

185

The check for whether a commandline argument has been set can be [%1]==[], but, as Dave Costa points out, "%1"=="" will also work.

I also fixed a syntax error in the usage echo to escape the greater-than and less-than signs. In addition, the exit needs a /B argument otherwise CMD.exe will quit.

@echo off

if [%1]==[] goto usage
@echo This should not execute
@echo Done.
goto :eof
:usage
@echo Usage: %0 ^<EnvironmentName^>
exit /B 1
zvava
  • 101
  • 1
  • 3
  • 14
Iain
  • 10,433
  • 16
  • 56
  • 62
  • 26
    [%1]==[] is better than "%1"=="" because it will correctly handle the case where %1 itself contains double quotes. "%1"=="" will error with an "unexpected at this time" message. – tekumara Feb 08 '12 at 01:03
  • 2
    Note that, if you aren't using commandline arguments but `set` variables (I don't know the correct batch terminology), you might want to use `"%myvar%"==""` because if `myvar` has spaces in it and is not quoted, you will get the "unexpected at this time" message. – Pat May 30 '12 at 20:15
  • 1
    @Pat SET variables could be checked with `IF NOT DEFINED VarName` block. Also +1 to tukushan for not using quotes in comparison. Just don't do it. Never. – Fr0sT Jun 20 '14 at 07:03
  • 12
    `"%~1"==""` will also work and take care of the case where %1 has double quotes – Drakkim Mar 25 '15 at 03:00
  • 10
    `"%~1"==""` handles spaces in the variable while the `[]` version does not. – Okkenator Apr 14 '15 at 11:00
28

A more-advanced example:

⍟ unlimited arguments.

⍟ exist on file system (either file or directory?) or a generic string.

⍟ specify if is a file

⍟ specify is a directory

no extensions, would work in legacy scripts!

minimal code ☺

@echo off

:loop
      ::-------------------------- has argument ?
      if ["%~1"]==[""] (
        echo done.
        goto end
      )
      ::-------------------------- argument exist ?
      if not exist %~s1 (
        echo not exist
      ) else (
        echo exist
        if exist %~s1\NUL (
          echo is a directory
        ) else (
          echo is a file
        )
      )
      ::--------------------------
      shift
      goto loop
      
      
:end

pause

✨ other stuff..✨

■ in %~1 - the ~ removes any wrapping " or '.

■ in %~s1 - the s makes the path be DOS 8.3 naming, which is a nice trick to avoid spaces in file-name while checking stuff (and this way no need to wrap the resource with more "s.

■ the ["%~1"]==[""] "can not be sure" if the argument is a file/directory or just a generic string yet, so instead the expression uses brackets and the original unmodified %1 (just without the " wrapping, if any..)

if there were no arguments of if we've used shift and the arg-list pointer has passed the last one, the expression will be evaluated to [""]==[""].

■ this is as much specific you can be without using more tricks (it would work even in windows-95's batch-scripts...)

■ execution examples

save it as identifier.cmd

it can identify an unlimited arguments (normally you are limited to %1-%9), just remember to wrap the arguments with inverted-commas, or use 8.3 naming, or drag&drop them over (it automatically does either of above).


this allows you to run the following commands:

identifier.cmd c:\windows and to get

exist
is a directory
done

identifier.cmd "c:\Program Files (x86)\Microsoft Office\OFFICE11\WINWORD.EXE" and to get

exist
is a file
done

⓷ and multiple arguments (of course this is the whole-deal..)

identifier.cmd c:\windows\system32 c:\hiberfil.sys "c:\pagefile.sys" hello-world

and to get

exist
is a directory
exist
is a file
exist
is a file
not exist
done.

naturally it can be a lot more complex, but nice examples should always be simple and minimal. :)

Hope it helps anyone :)

published here:CMD Ninja - Unlimited Arguments Processing, Identifying If Exist In File-System, Identifying If File Or Directory

and here is a working example that takes any amount of APK files (Android apps) and installs them on your device via debug-console (ADB.exe): Make The Previous Post A Mass APK Installer That Does Not Uses ADB Install-Multi Syntax

Community
  • 1
  • 1
  • The CMD Ninja link didn't work for me, but an [archived version](https://web.archive.org/web/20160718175942/http://icompile.eladkarako.com/cmd-unlimited-arguments-identifying-directory-file-or-none/) did. Very nice summary, BTW! – Sz. Aug 23 '22 at 15:33
  • You can just use :eof and then there's no need for label. It's implicit. https://ss64.com/nt/goto.html – JGFMK Oct 16 '22 at 20:33
16

Get rid of the parentheses.

Sample batch file:

echo "%1"

if ("%1"=="") echo match1

if "%1"=="" echo match2

Output from running above script:

C:\>echo "" 
""

C:\>if ("" == "") echo match1 

C:\>if "" == "" echo match2 
match2

I think it is actually taking the parentheses to be part of the strings and they are being compared.

zvava
  • 101
  • 1
  • 3
  • 14
Dave Costa
  • 47,262
  • 8
  • 56
  • 72
  • 1
    `if "%1"==""` will crash if the arg has spaces. For example: `run.bat "a b"`. @amr has the best answer to use `if "%~1"==""` – wisbucky Oct 25 '17 at 18:19
6
IF "%~1"=="" GOTO :Usage

~ will de-quote %1 if %1 itself is quoted.

" " will protect from special characters passed. for example calling the script with &ping

Amr Ali
  • 3,020
  • 1
  • 16
  • 11
  • 1
    This is the best answer. The other answers work for some cases, but will fail for more special cases like `run.bat "a b"` – wisbucky Oct 25 '17 at 18:23
  • @wisbucky That doesn't seem to mess up [the accepted answer](https://stackoverflow.com/a/830566/1028230). What am I missing? – ruffin Nov 30 '17 at 23:37
  • @ruffin, Example: `run.bat ""` will not be caught by with `[%1]==[]`. – wisbucky Dec 01 '17 at 01:26
4

This is the same as the other answers, but uses only one label and puts the usage first, which additionally makes it serve as a kind of documentation commend of the script which is also usually placed at the top:

@echo off
:: add other test for the arguments here...
if not [%1]==[] goto main
:: --------------------------
echo This command does something.
echo.
echo %0 param%%1 param%%2
echo       param%%1 the file to operate on
echo       param%%1 another file

:: --------------------------
exit /B 1

:main
:: --------------------------
echo do something with all arguments (%%* == %*) here...

However, if you don't have to use cmd/batch, use bash on WSL or powershell, they have more sane syntax and less arcane features.

masterxilo
  • 2,503
  • 1
  • 30
  • 35
1
IF "%1"=="" GOTO :Continue
.....
.....
:Continue
IF "%1"=="" echo No Parameter given
joshp
  • 1,886
  • 2
  • 20
  • 28
Howard Rothenburg
  • 1,220
  • 1
  • 11
  • 7
0

IF "%1"=="" will fail, all versions of this will fail under certain poison character conditions. Only IF DEFINED or IF NOT DEFINED are safe

  • 1
    `if [not] defined ...` doesn't work with parameters like `%1`. Do you have an example, where `if "%~1" ...` doesn't work? – Stephan Dec 26 '17 at 18:44
  • Here is an easy example for code injection. Create a file called `unsafe.bat` with content ``if "%~1"=="" ( echo hello )``. Now run from Powershell the following ``.\unsafe.bat "_`" neq `"`" echo Pwned &::"``. Also run the same Powershell arguments with the community answer https://stackoverflow.com/a/34552964/1490584 . You will see that batch arguments are quite unsafe by default – Simon Streicher Sep 14 '21 at 07:09
0

You can have a multiline if statement. "if not defined 1" didn't work.

if "%1"=="" (
  echo Usage:   ApplyImage WimFileName 
  exit 1
)
js2010
  • 23,033
  • 6
  • 64
  • 66