Rob van der Woude's Scripting Pages

Comments

Regardless of the programming or scripting language used, it is always a good idea to insert comments in scripts, explaining what the next lines or block of code is trying to accomplish, how and/or why.

Comments in batch files are usually placed in lines starting with REM (REMarks).

If you have many lines REMed out, this may slow down COMMAND.COM's processing of the batch file.

As you probably know, COMMAND.COM reads a batch file, executes one command line, reads the batch file again, executes the next command line, etcetera.
This means each comment line causes one extra reread of the batch file; no problem when read from harddisk, but it may slow down batch file execution from slow floppy or network drives.

A workaround I have seen many times (back in the old days, when I was young, and dinosaurs roamed the Earth and harddisks were 20MB) is to convert the comment line to a label by starting the line with a colon ( : ).
COMMAND.COM skips labels it doesn't have to jump to.

This method has the disadvantage that your batch file may "accidently" really use the label to jump to.

As Marc Stern points out in one of his MS-DOS batch files Tips & Tricks, this can be solved by using a double colon ( :: ) as the first characters of the comment line.
That way, the label is invalid but still treated as a label, and skipped (i.e. the next line is read immediately by COMMAND.COM, without the need to reopen the batch file). This may speed up reading large blocks of comment lines from slow (floppy) drives.

This same trick works in CMD.EXE (the command processor in Windows NT 4 and later) as well (not sure about OS/2 though)...

...but with some restrictions!

REM is a true command that may be used anywhere within a command line.
Though I doubt there is much use for a command like:

IF EXIST C:\AUTOEXEC.BAT REM AUTOEXEC.BAT exists

it is valid and won't generate an error message in any DOS or Windows version.

Labels, on the other hand, whether valid or not, should always start at the first non-whitespace character in a command line.

REM Comment line 1
	REM Comment line 2
:Label1
	:Label2
:: Comment line 3
	:: Comment line 4
IF EXIST C:\AUTOEXEC.BAT REM AUTOEXEC.BAT exists

are all allowed.
However,

IF EXIST C:\AUTOEXEC.BAT :: AUTOEXEC.BAT exists

will result in a Syntax error message.

A true pitfall are code blocks, several commands grouped between parentheses and interpreted as a single command line by CMD.EXE!

IF EXIST C:\AUTOEXEC.BAT (
	:: Comment line 1
	ECHO Do something
	:: Comment line 2
)

will result in an error message stating:

) was unexpected at this time.

and:

IF EXIST C:\AUTOEXEC.BAT (
	:: Comment line 1
	ECHO Do something
	:: Comment line 2
	:: Comment line 3
)

will result in another error message:

Do something
The system cannot find the drive specified.

The same is true for FOR loops.
Try and see for yourself:

FOR %%A IN (1 2 3) DO (
	:: Comment line 1
	ECHO Do something
	:: Comment line 2
)

and:

FOR %%A IN (1 2 3) DO (
	:: Comment line 1
	ECHO Do something
	:: Comment line 2
	:: Comment line 3
)

will also result in error messages.

The errors are caused by labels being used within code blocks.

What may come as a surprise is that the following code does work flawlessly:

FOR %%A IN (1 2 3) DO (
	:: Comment line 1
	ECHO Do something
	:: Comment line 2
	ECHO Do something
)

It turns out that a single :: comment line, immediately followed by a non-blank command line, will work even inside code blocks!

Source: a discussion on comment styles on StackOverflow.com

Replace the double colons by REM statements and these samples will all run without a glitch.
Better still, don't use comments within code blocks at all, but place them just before the code blocks instead:

:: Comment line 1
:: Comment line 2
:: Comment line 3
FOR %%A IN (1 2 3) DO (
	ECHO Do something
)

or:

REM Comment line 1
REM Comment line 2
REM Comment line 3
FOR %%A IN (1 2 3) DO (
	ECHO Do something
)

A Mystery:

(
	REM comment1
	ECHO comment1
)

(REM comment2 & ECHO comment2)

REM comment3 & ECHO comment3

ECHO comment4

The code above use 3 code blocks, each with a REM command followed by an ECHO command.
The 3 code blocks are followed by a fourth "stand-alone" ECHO command.
The 3 code blocks are supposed to behave more or less identically, at least in older versions like Windows NT 4 and 2000...

Well, in Windows 7 they don't!

D:\>test_REM_comments_in_code_blocks.bat

D:\>(
REM comment1
 ECHO comment1
)
comment1
D:\>
D:\>

comment1 is the only comment ECHOed.
The code block for comment2 only displays an empty line.
The code block for comment3 is never reached...

It would seem the code block for comment2 aborts the batch file without warning.
Remove that code block, and the rest will be executed as expected.

So, can you explain this behaviour...?

The answer can be found at the end of this page.

More information on the subject:

(Thanks for Lee Wilbur and Michael Klement)

 

A possible pitfall, pointed out by Joost Kop, is a REM to comment out a line that uses redirection, as in:

REM DIR > logfile.log

In CMD.EXE (Windows NT 4 and later) the line is completely ignored (as was probably intended), but COMMAND.COM (MS-DOS, Windows 9x) interprets this line as "redirect the output of REM to logfile.log", thus emptying the file logfile.log or creating a 0 bytes file logfile.log.

Note: I would like to mention one situation where I always prefer REM over double colons: batch files for silent installations.
Why?
I always leave out the @ECHO OFF since silent installations will usually run in the background.
When testing, however, I will run the batch files interactively, and then the REMed comments will be displayed (remember, no @ECHO OFF) because they are commands, not labels.

Summarizing:

 

Pipe REM to block Standard Input

A really useful trick is to use REM combined with piping, as in:

REM | CHOICE /C:AB /T:A,5 > NUL

The CHOICE command in itself would time out after 5 seconds (/T), except if someone presses a key not specified by /C, in which case the count down would be aborted.
By using REM and piping its (always empty) standard output to CHOICE's standard input, this standard input will not receive keypresses from the console (keyboard) anymore. So pressing a button neither speeds up CHOICE nor stops it.
(I borrowed this technique from "Outsider", one of the alt.msdos.batch newsgroup's "regulars", and added the /C parameter to make it language independent)

Note: This trick will work in COMMAND.COM only, not in CMD.EXE.
In CMD.EXE everything after the REM "command" is considered comment, including the pipe symbol.
For CMD.EXE, the following command could be used (Windows XP and later):

TYPE NUL | CHOICE /C:AB /T:A,5 > NUL

Read my wait page to find out how to set delays in Windows NT 4 and later.

 

Comment blocks

Several languages allow complete code blocks to be commented out by using /* and */ "tags".
Rexx, for example, will treat the whole text marked red as comment:

Say "This line is true code"

/*
But this line is comment.
And so is this line.
And this one...
*/

The batch language doesn't have comment blocks, though there are ways to accomplish the effect:

@ECHO OFF
REM Do something
  •
  •
REM End of code

REM Start of comment block 1
GOTO EndComment1
This line is comment.
And so is this line.
And this one...
:EndComment1

Or, if the comment block appears at the end of the batch file:

@ECHO OFF
REM Do something
  •
  •
REM End of code; use GOTO:EOF instead of EXIT for Windows NT and later
EXIT

Start of comment block at end of batch file
This line is comment.
And so is this line.
And this one...

Leo Gutierrez Ramirez came up with an even shorter way to accomplish a comment block at the end of a batch file:

@ECHO OFF
REM Do something
  •
  •
REM End of code

(Start of comment block at end of batch file
This line is comment.
And so is this line.
And this one...
Just make sure you never use a closing parenthesis.
Note: This trick does have one major disadvantage: the use of parentheses in the comment block is not allowed.

 

Mystery Solved

Recently, Vasco Rato showed me the solution to the mysteriously disappearing code.

If you read Leo Gutierrez Ramirez' trick of the missing closing parenthesis, you'll see that that is exactly what happens.
The following line of code:

(REM comment2 & ECHO comment2)

is equivalent to

(REM whatever

since everything following the REM statement, including the closing parenthesis, is comment, i.e. not interpreted!

Since there were no other parentheses in the "mystery code block" after this comment, everything from the opening parenthesis before the REM statement up to the end of the code is then a "Leo Gutierrez Ramirez style" comment block.

As Vasco states: everything behaves as one would expect it to.

Thanks Vasco and Leo


page last modified: 2019-03-12; loaded in 0.0054 seconds