Careful with those parentheses

Start with a fresh, minimal batch file:
@ECHO OFF
IF 1==1 (
        ECHO foo (bar) baz
) ELSE (
        ECHO gak
 )
Run it and enjoy the following error message: baz was unexpected at this time.

What happened here?

Well, look at the following code:
IF 1==1 (ECHO foo)
Where would you expect the ECHO command to end? Right, just before the closing paren. Let's rewrite that line:
IF 1==1 (
        ECHO foo
 )
Still looks nice. But what happens if you want to output a closing parenthesis (maybe for a smiley) inside an IF block?A straig­htforward idea of writing this would be
IF 1==1 (
        ECHO :-)
 )
Our experience with ECHO tells us that it prints the whole line, unless interrupted by things like & or >. And of course ECHO :-) works just fine from the command line. Put into an IF block, however, yields an error:
IF 1==1 (ECHO :-))
) was unexpected at this time.
And from here it's probably obvious what happened. The first closing parenthesis will end the IF block, kinda like the first */ will end a comment in C. Cmd's behavior here makes sense for single-line IFs but in my opinion it is a bit annoying when going multi-line.Now we know what to look for, it'd be nice to know how to prevent this in future. The first idea would be to move the interior of the block in a subroutine:
IF 1==1 CALL :SUB
GOTO :EOF
:SUB
ECHO :-)
GOTO :EOF
This works, but using a subroutine for a single line is not very nice (OK, may depend on how long the line is). Another option would be to put the closing parenthesis into an environment variable:
SET P=)
IF 1==1 (
        ECHO :-%P%
 )
Still not nice but at least it doesn't rip the code apart. The easiest way, however, would be to use escaping. The escape character in cmd is ^, so the code would look the following:
IF 1==1 (
        ECHO :-^)
 )
We just got our smiley a hooked nose.

Note, that if you have the parentheses in a variable (such as the 32-bit program files directory on x64 systems), then you need to either use delayed expansion or a subroutine (to avoid the parentheses).

Things to learn from this: The escape character is applicable anywhere in batch files. It causes every character to be recognized as not being part of the syntax.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Parameterizing for loops with parameters containing parentheses

When the parentheses are passed within some parameter or variable into a for loop such as this one in a cmd script:

for /f „usebackq tokens=1–5“ %%S in (sc %PAR%) DO (IF /I [„%%U“] EQU [„FAILED“] (endlocal & exit /b %%V))

where in this case %PAR% may be an SDDL string containing parentheses – even escaping them won't help. The escaping is gone when the %PAR% is replaced with the parameters content and breaks the for loop when it is finally executed.

Does anybody know a way around this?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.