How can I check if an argument is defined when starting/calling a batch file?
Asked Answered
D

8

118

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?

Deedeeann answered 6/5, 2009 at 16:45 Comment(3)
Possible duplicate of What is the proper way to test if a parameter is empty in a batch file?Cumulation
@Cumulation - 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?Kermanshah
@KevinFegan because the other question has more views and more answers.Cumulation
Z
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
Zahara answered 6/5, 2009 at 16:45 Comment(5)
[%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.Incretion
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.Archibold
@Archibold 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.Nummary
"%~1"=="" will also work and take care of the case where %1 has double quotesBlazonry
"%~1"=="" handles spaces in the variable while the [] version does not.Omaromara
D
29

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

Drennen answered 1/1, 2016 at 1:42 Comment(2)
The CMD Ninja link didn't work for me, but an archived version did. Very nice summary, BTW!Cameraman
You can just use :eof and then there's no need for label. It's implicit. ss64.com/nt/goto.htmlDecathlon
C
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.

Cribb answered 6/5, 2009 at 16:51 Comment(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"==""Aposematic
M
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

Mcmillan answered 24/11, 2014 at 16:50 Comment(3)
This is the best answer. The other answers work for some cases, but will fail for more special cases like run.bat "a b"Aposematic
@Aposematic That doesn't seem to mess up the accepted answer. What am I missing?Steiner
@ruffin, Example: run.bat "" will not be caught by with [%1]==[].Aposematic
I
5

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.

Ineffable answered 27/12, 2018 at 16:13 Comment(0)
M
2
IF "%1"=="" GOTO :Continue
.....
.....
:Continue
IF "%1"=="" echo No Parameter given
Mcchesney answered 1/5, 2012 at 21:52 Comment(1)
This crashes for run.bat "a b"Aposematic
C
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

Conspectus answered 26/12, 2017 at 18:33 Comment(2)
if [not] defined ... doesn't work with parameters like %1. Do you have an example, where if "%~1" ... doesn't work?Schumer
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://mcmap.net/q/101709/-how-can-i-check-if-an-argument-is-defined-when-starting-calling-a-batch-file . You will see that batch arguments are quite unsafe by defaultMeleager
D
0

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

if "%1"=="" (
  echo Usage:   ApplyImage WimFileName 
  exit 1
)
Delectation answered 23/8, 2023 at 18:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.