[batch-file] Using multiple IF statements in a batch file

When using more than 1 IF statement, is there a special guideline that should be followed? Should they be grouped? Should I use parenthesis to wrap the command(s)?

An example to use would be:

IF EXIST somefile.txt IF EXIST someotherfile.txt SET var=somefile.txt,someotherfile.txt

This question is related to batch-file if-statement cmd

The answer is


is there a special guideline that should be followed

There is no "standard" way to do batch files, because the vast majority of their authors and maintainers either don't understand programming concepts, or they think they don't apply to batch files.

But I am a programmer. I'm used to compiling, and I'm used to debuggers. Batch files aren't compiled, and you can't run them through a debugger, so they make me nervous. I suggest you be extra strict on what you write, so you can be very sure it will do what you think it does.

There are some coding standards that say: If you write an if statement, you must use braces, even if you don't have an else clause. This saves you from subtle, hard-to-debug problems, and is unambiguously readable. I see no reason you couldn't apply this reasoning to batch files.

Let's take a look at your code.

IF EXIST somefile.txt IF EXIST someotherfile.txt SET var=somefile.txt,someotherfile.txt

And the IF syntax, from the command, HELP IF:

IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXISTS filename command

...

IF EXIST filename (
  command
) ELSE (
  other command
)

So you are chaining IF's as commands.

If you use the common coding-standard rule I mentioned above, you would always want to use parens. Here is how you would do so for your example code:

IF EXIST "somefile.txt" (
  IF EXIST "someotherfile.txt" (
    SET var="somefile.txt,someotherfile.txt"
  )
)

Make sure you cleanly format, and do some form of indentation. You do it in code, and you should do it in your batch scripts.

Also, you should also get in the habit of always quoting your file names, and getting the quoting right. There is some verbiage under HELP FOR and HELP SET that will help you with removing extra quotes when re-quoting strings.

Edit

From your comments, and re-reading your original question, it seems like you want to build a comma separated list of files that exist. For this case, you could simply use a bunch of if/else statements, but that would result in a bunch of duplicated logic, and would not be at all clean if you had more than two files.

A better way is to write a sub-routine that checks for a single file's existence, and appends to a variable if the file specified exists. Then just call that subroutine for each file you want to check for:

@ECHO OFF
SETLOCAL

REM Todo: Set global script variables here
CALL :MainScript
GOTO :EOF

REM MainScript()
:MainScript
  SETLOCAL

  CALL :AddIfExists "somefile.txt" "%files%" "files"
  CALL :AddIfExists "someotherfile.txt" "%files%" "files"

  ECHO.Files: %files%

  ENDLOCAL
GOTO :EOF

REM AddIfExists(filename, existingFilenames, returnVariableName)
:AddIfExists
  SETLOCAL

  IF EXIST "%~1" (
    SET "result=%~1"
  ) ELSE (
    SET "result="
  )

  (
    REM Cleanup, and return result - concatenate if necessary
    ENDLOCAL

    IF "%~2"=="" (
      SET "%~3=%result%"
    ) ELSE (
      SET "%~3=%~2,%result%"
    )
  )
GOTO :EOF

IF EXIST "somefile.txt" (
  IF EXIST "someotherfile.txt" (
    SET var="somefile.txt","someotherfile.txt"
  )
) ELSE (
  CALL :SUB
)
:SUB
ECHO Sorry... nothin' there.
GOTO:EOF

Is this feasible?

SETLOCAL ENABLEDELAYEDEXPANSION
IF EXIST "somefile.txt" (
  SET var="somefile.txt"
  IF EXIST "someotherfile.txt" (
    SET var=!var!,"someotherfile.txt"
  )
) ELSE (
  IF EXIST "someotherfile.txt" (
    SET var="someotherfile.txt"
  ) ELSE (
  GOTO:EOF
  )
)

The explanation given by Merlyn above is pretty complete. However, I would like to elaborate on coding standards.

When several IF's are chained, the final command is executed when all the previous conditions are meet; this is equivalent to an AND operator. I used this behavior now and then, but I clearly indicate what I intend to do via an auxiliary Batch variable called AND:

SET AND=IF

IF EXIST somefile.txt %AND% EXIST someotherfile.txt SET var=somefile.txt,someotherfile.txt

Of course, this is NOT a true And operator and must not be used in combination with ELSE clause. This is just a programmer aid to increase the legibility of an instruction that is rarely used.

When I write Batch programs I always use several auxiliary variables that I designed with the sole purpose of write more readable code. For example:

SET AND=IF
SET THEN=(
SET ELSE=) ELSE (
SET NOELSE=
SET ENDIF=)
SET BEGIN=(
SET END=)
SET RETURN=EXIT /B

These variables aids in writting Batch programs in a much clearer way and helps to avoid subtle errors, as Merlyn suggested. For example:

IF EXIST "somefile.txt" %THEN%
  IF EXIST "someotherfile.txt" %THEN%
    SET var="somefile.txt,someotherfile.txt"
  %NOELSE%
  %ENDIF%
%NOELSE%
%ENDIF%

IF EXIST "%~1" %THEN%
  SET "result=%~1"
%ELSE%
  SET "result="
%ENDIF%

I even have variables that aids in writting WHILE-DO and REPEAT-UNTIL like constructs. This means that Batch variables may be used in some degree as preprocessor values.


You can structurize your batch file by using goto

IF EXIST somefile.txt goto somefileexists
goto exit

:somefileexists
IF EXIST someotherfile.txt SET var=...

:exit

Batch files have really very limited logic powers so the best you can hope to come up with is a good workaround that indirectly achieves what you want. That's not to say that you should feel they are inferior to a real language - they still demand the same attention to detail and manual debugging as a real application. It's just that you'll need to work a lot harder to make them do what you want in a robust manner.

For the OP's question it sounds like you require two specific files to exist. Just use a tally:

IF EXIST somefile.txt (
    set /a file1_status=1
)

IF EXIST someotehrfile.txt (
    set /a file2_status=1
)

set /a file_status_result=file1_status + file2_status

if %file_status_result% equ 2 (
    goto somefileexists
)

goto exit

:somefileexists
IF EXIST someotherfile.txt SET var=...

:exit

My example uses 3 variables, but you could just add 1 to file_result_status if the file exists. But if you want more granular control later in your batch file you can record the result for each file as I have done so you don't have to keep checking if a file exists later on.


Examples related to batch-file

'ls' is not recognized as an internal or external command, operable program or batch file '' is not recognized as an internal or external command, operable program or batch file XCOPY: Overwrite all without prompt in BATCH CanĀ“t run .bat file under windows 10 Execute a batch file on a remote PC using a batch file on local PC Windows batch - concatenate multiple text files into one How do I create a shortcut via command-line in Windows? Getting Error:JRE_HOME variable is not defined correctly when trying to run startup.bat of Apache-Tomcat Curl not recognized as an internal or external command, operable program or batch file Best way to script remote SSH commands in Batch (Windows)

Examples related to if-statement

How to use *ngIf else? SQL Server IF EXISTS THEN 1 ELSE 2 What is a good practice to check if an environmental variable exists or not? Using OR operator in a jquery if statement R multiple conditions in if statement Syntax for an If statement using a boolean How to have multiple conditions for one if statement in python Ifelse statement in R with multiple conditions If strings starts with in PowerShell Multiple conditions in an IF statement in Excel VBA

Examples related to cmd

'ls' is not recognized as an internal or external command, operable program or batch file '' is not recognized as an internal or external command, operable program or batch file XCOPY: Overwrite all without prompt in BATCH VSCode Change Default Terminal How to install pandas from pip on windows cmd? 'ls' in CMD on Windows is not recognized Command to run a .bat file VMware Workstation and Device/Credential Guard are not compatible How do I kill the process currently using a port on localhost in Windows? how to run python files in windows command prompt?