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

127,724

Solution 1

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

Solution 2

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

Solution 3

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.

Solution 4

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

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

Share:
127,724

Related videos on Youtube

Daniel Fortunov
Author by

Daniel Fortunov

Daniel Fortunov holds a First-Class BSc Honours degree in Applied Computer Science and Cybernetics from the University of Reading, where he was awarded the Usher/Whitfield Cybernetics Prize for Best BSc/BEng Degree Result and travelled to New York to present original research at the IEEE EMBS conference. He currently works in London as a software developer in the financial sector.

Updated on July 08, 2022

Comments

  • Daniel Fortunov
    Daniel Fortunov almost 2 years

    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
      double-beep over 5 years
    • Kevin Fegan
      Kevin Fegan almost 4 years
      @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?
    • double-beep
      double-beep almost 4 years
      @KevinFegan because the other question has more views and more answers.
  • tekumara
    tekumara over 12 years
    [%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.
  • Pat
    Pat about 12 years
    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.
  • Fr0sT
    Fr0sT about 10 years
    @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.
  • Drakkim
    Drakkim over 9 years
    "%~1"=="" will also work and take care of the case where %1 has double quotes
  • Okkenator
    Okkenator about 9 years
    "%~1"=="" handles spaces in the variable while the [] version does not.
  • wisbucky
    wisbucky over 6 years
    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
    wisbucky over 6 years
    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
    wisbucky over 6 years
    This crashes for run.bat "a b"
  • ruffin
    ruffin over 6 years
    @wisbucky That doesn't seem to mess up the accepted answer. What am I missing?
  • wisbucky
    wisbucky over 6 years
    @ruffin, Example: run.bat "" will not be caught by with [%1]==[].
  • Stephan
    Stephan over 6 years
    if [not] defined ... doesn't work with parameters like %1. Do you have an example, where if "%~1" ... doesn't work?
  • Simon Streicher
    Simon Streicher almost 3 years
    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 stackoverflow.com/a/34552964/1490584 . You will see that batch arguments are quite unsafe by default