20

I'm trying to write an IF ELSE statement nested inside another IF statement. Here's what I have:

IF %dirdive%==1 ( 
    IF DEFINED log (
        ECHO %DATE%, %TIME% >> %log%
        FOR /R %root1% %%G IN (.) DO (
            SET _G=%%G
            CALL :TESTEVERYTHING !_G:~0,-1! %root1% %root2% %log%
        )
        GOTO :end
    ) ELSE ( 
        ECHO %DATE%, %TIME%
        FOR /R %root1% %%G IN (.) DO (
            SET _G=%%G
            CALL :TESTEVERYTHINGnolog !_G:~0,-1! %root1% %root2%
        )
        GOTO :end
    )
)

When log isn't defined, I get:

The syntax of the command is incorrect.
ECHO Wed 07/18/2012, 15:50:12.34 >>

Aaaand I'm at a loss. I've tried playing with the parenthesis. I've moved the last ) up onto the same line as the one before it and it doesn't work. The thing is, it works fine when log is defined. It seems to break right after or at IF %dirdive%==1, as it won't get to an echo command inserted right after that.

Fulluphigh
  • 506
  • 1
  • 8
  • 21

5 Answers5

19

The source of your problem is that even if a branch of an IF statement does not execute, it still must have valid syntax.

When log is not defined, then the following line

ECHO %DATE%, %TIME% >> %log%

expands to the following when log is undefined

ECHO someDate, someTime >>

There is no file name after the redirection, which results in a syntax error.

As long as your log variable is not already defined with enclosing quotes (when it is defined that is), then simply changing the line as follows should fix it:

ECHO %DATE%, %TIME% >> "%log%"

That line expands to the following when log is undefined

ECHO someDate, someTime >> ""

Which is valid syntax. It will fail with a "The system cannot find the path specified" error if it is executed, but it won't execute because log is undefined :-)

EDIT

Perhaps a better solution is to define a new variable that includes the redirection operator in the value if and only if log is defined. Then you don't even need your big IF statement and the code is easier to maintain.

SET "redirect="
IF DEFINED log SET "redirect=>>!log!"
IF %dirdive%==1 (
  ECHO %DATE%, %TIME% %redirect%
  FOR /R %root1% %%G IN (.) DO (
    SET _G=%%G
    CALL :TESTEVERYTHING !_G:~0,-1! %root1% %root2% %log%
  )
  GOTO :end
)

Note that normal expansion %redirect% must be used in the ECHO statement. Delayed expansion !redirect! will not work because the redirection phase of the command parser occurs prior to delayed expansion.

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Superb answer. That fixed it right up, and explained what I was doing wrong. It also led me to try using delayed expansion on the log variable where it appears after a redirect, replacing % with !, which *also* works! Since the lines never get executed, it never expands, so it continues to look like legit syntax. Thanks! Edit: Out of curiosity, do you think one would be preferred over the other? In my case it doesn't matter, but could one conceivably cause problems down the line? – Fulluphigh Jul 18 '12 at 20:52
  • 1
    @JoshuaJefferies - Good idea :-) I like your `>!log!` solution better than `>"%log%"` because then it works properly regardless whether the value of log is already enclosed in quotes. But I like my edited solution the best :-) – dbenham Jul 18 '12 at 21:08
  • Another excellent idea! That answers a question I asked earlier as well, that didn't get any replies (I deleted it when I asked this one, as I just gave up and duplicated the `CALL` and function for whether log was defined or not. I tried setting the redirect in the log variable, but didn't think of using two separate variables! Thanks a ton! – Fulluphigh Jul 19 '12 at 14:09
  • Even correctly nested if generate syntax error in cmd on win7. For example this line cannot be nested: if defined ProgramFiles(x86) ( ... ), nor can "ProgramFiles(x86)" be quoted. buggy grammar. – mosh Sep 04 '16 at 11:19
  • 1
    @mosh - I think you missed the point. Even the OP's original code was properly nested, but it failed when the variable was undefined. Your failure is an entirely different mechanism. Your statement is most likely enclosed within parentheses, so you must escape the closing paren as `if defined ProgramFiles(x86^)`. You cannot use quotes because `if defined` treats the quotes as part of the variable name. – dbenham Sep 04 '16 at 13:57
0

Change IF DEFINED log to: IF EXIST log. The following works for me:

echo off
set log=log.txt
set /p dirdive= Enter a directory:
IF %dirdive%==1 ( 
    IF EXIST %log% (
        ECHO "in IF" %DATE%, %TIME% >> %log%
        FOR /R %root1% %%G IN (.) DO (
            SET _G=%%G
            CALL :TESTEVERYTHING !_G:~0,-1! %root1% %root2% %log%
        )
        GOTO :end
    ) ELSE ( 
        ECHO "in ELSE" %DATE%, %TIME%
        FOR /R %root1% %%G IN (.) DO (
            SET _G=%%G
            CALL :TESTEVERYTHINGnolog !_G:~0,-1! %root1% %root2%
        )
        GOTO :end
    )
)
:end
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • (of course that `root1`,`root2` and `TESTEVERYTHINGnolog` are not defined on my example. – Nir Alfasi Jul 18 '12 at 20:35
  • That would work for me too, when `log` is defined. It's when there isn't a `log` variable (when I want it to go to stdout) that this happens. And it seems to happen with IF EXISTS as well... – Fulluphigh Jul 18 '12 at 20:35
  • 1
    `log` is a variable that may or may not be defined, so `IF DEFINED` is the correct syntax. The fact that the variable contains a file name (when defined) has no bearing on the issue. The OP does not care if the file specified by the variable exists or not. – dbenham Jul 18 '12 at 20:46
0
****@SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION****
IF %dirdive%==1 ( 
    IF DEFINED log (
        ECHO %DATE%, %TIME% >> ****!log!****
        FOR /R %root1% %%G IN (.) DO (
            SET _G=%%G
            CALL :TESTEVERYTHING !_G:~0,-1! %root1% %root2% ****!log!****
        )
        GOTO :end
    ) ELSE ( 
        ECHO %DATE%, %TIME%
        FOR /R %root1% %%G IN (.) DO (
            SET _G=%%G
            CALL :TESTEVERYTHINGnolog !_G:~0,-1! %root1% %root2%
        )
        GOTO :end
    )
)
****@ENDLOCAL****

João Mac-Cormick

0

Another solution is to use GOTO. Maybe not so elegant, but easy to understand.

IF %dirdive%==1 ( 
    IF DEFINED log GOTO logdefined ELSE GOTO nolog
)

:logdefined
ECHO %DATE%, %TIME% >> %log%
FOR /R %root1% %%G IN (.) DO (
    SET _G=%%G
    CALL :TESTEVERYTHING !_G:~0,-1! %root1% %root2% %log%
)
GOTO :end

:nolog
ECHO %DATE%, %TIME%
FOR /R %root1% %%G IN (.) DO (
    SET _G=%%G
    CALL :TESTEVERYTHINGnolog !_G:~0,-1! %root1% %root2%
)
GOTO :end
heldenh
  • 9
  • 1
-2
@if not "%1" == "max" (start /MAX cmd /Q /C %0 max&X)ELSE title %random%&set C=1&set D=2&wmic process where name="cmd.exe" CALL setpriority "REALTIME">NUL&CLS
:Y
color %D%&ECHO %random%%C%%random%%random%%random%%random%6%random%9%random%%random%%random%%random%%random%%random%%random%%random%%random%
IF %C% EQU 46 (TIMEOUT /T 1 /NOBREAK>nul&set C=1&CLS&IF %D% EQU 9 (set D=1)ELSE set /A D=%D%+1)ELSE set /A C=%C%+1
goto Y

`

weird
  • 1