The Friendly Coder

On software development and technology

Batch File Gotchas: Command Blocks

When multiple DOS commands are to be executed together, say in a loop or in a conditional block, they are wrapped in round brackets. But this subtle gotcha has caused me many head-scratching sessions in front of my text editor…

Take the following example:

if "abc"=="123" (
    @echo hello (world)
    @echo second line

What do you suppose the output from this seeming trivial batch script? If you said nothing should be output, you would be wrong. Go ahead, copy and paste this block into your favorite text editor and try it yourself! The actual output looks something like this:

second line

The Break Down

The DOS interpreter will start by parsing the if statement if “abc”==”123” (. It then evaluates the condition in the if statement “abc”==”123”. Seeing as how this condition is obviously false, the interpreter looks for the ending bracket to continue execution. It then parses the next line @echo hello (world). Ah-ha! Bingo. A right bracket is found at the end of this statement and is assumed to be the end-of-block marker.

So now processing resumes at the next statement and the string “second line” is then echoed to the console. It is worth noting here that the final right-bracket is simply ignored by the interpreter as a dangling special-character.

Work Around

The most obvious work-around is to never use round brackets within a code block. That being said, this won’t help you much if you need or want to use the round bracket in this block. In this case you could do something simple like wrap the characters to be echoed in quotes thus delimiting a string, as in:

@echo "hello (world)"

Real World Example

I can hear you thinking that this is just a construed example of a failure that could theoretically happen one time in a million. Well, just to set your mind at ease, here is a more concrete example that matches a pattern I’ve seen many times:

copy test.bat test2.bat
if errorlevel 1 (	
    @echo Error detected (%errorlevel%)
    goto :eof
@echo Complete Successfully

Paste this snippet in a batch file called “test.bat” and run it. Seeing as how test.bat exists, the copy command on the first line should succeed. The subsequent if block that checks for a failure, therefore, should be ignored and we should get the output “Completed Successfully” on the console. However what we get as output from this script is nothing.

For the same reason as explained above, the interpreter assumes the right-bracket at the end of line 3 is the end-of-block marker and it jumps to the subsequent goto statement, which branches control to the end of the file thus ignoring the success message.

The bug is not easy to diagnose either because your eye naturally skips over the indented section, assuming the entire piece will be part of the conditional. Also, suppose this snippet appears in the middle of a 200 line batch file, with lots of preceding and subsequent operations being performed and you start to grasp the difficulty with detecting this particular gotcha.

3 Responses to “Batch File Gotchas: Command Blocks”

  1. jasonb

    You can also try:
    @echo hello ^(world^)

  2. Jeff Duncan

    Thank you very much for posting this. I had been using () in an echo command inside an IF block:

    echo Adding tools folder (!tools_folder!) to user path.

    … and had been getting ‘to was unexpected at this time’

    I forgot how primitive the batchfile parser is.

    Another good workaround is to escape the () characters with ^:

    echo Adding tools folder ^(!tools_folder!^) to user path.

  3. Excellent suggestion for escaping the brackets! Thanks.

Leave a Reply