Which comment style should I use in batch files?
Solution 1
tl;dr: REM
is the documented and supported way to embed comments in batch files.
::
is essentially a blank label that can never be jumped to, whereas REM
is an actual command that just does nothing. In neither case (at least on Windows 7) does the presence of redirection operators cause a problem.
However, ::
is known to misbehave in blocks under certain circumstances, being parsed not as a label but as some sort of drive letter. I'm a little fuzzy on where exactly but that alone is enough to make me use REM
exclusively. It's the documented and supported way to embed comments in batch files whereas ::
is merely an artifact of a particular implementation.
Here is an example where ::
produces a problem in a FOR
loop.
This example will not work in a file called test.bat
on your desktop:
@echo off
for /F "delims=" %%A in ('type C:\Users\%username%\Desktop\test.bat') do (
::echo hello>C:\Users\%username%\Desktop\text.txt
)
pause
While this example will work as a comment correctly:
@echo off
for /F "delims=" %%A in ('type C:\Users\%username%\Desktop\test.bat') do (
REM echo hello>C:\Users\%username%\Desktop\text.txt
)
pause
The problem appears to be when trying to redirect output into a file. My best guess is that it is interpreting ::
as an escaped label called :echo
.
Solution 2
Comments with REM
A REM
can remark a complete line, also a multiline caret at the line end, if it's not the end of the first token.
REM This is a comment, the caret is ignored^
echo This line is printed
REM This_is_a_comment_the_caret_appends_the_next_line^
echo This line is part of the remark
REM followed by some characters .:\/=
works a bit different, it doesn't comment an ampersand, so you can use it as inline comment.
echo First & REM. This is a comment & echo second
But to avoid problems with existing files like REM
, REM.bat
or REM;.bat
only a modified variant should be used.
REM^;<space>Comment
And for the character ;
is also allowed one of ;,:\/=
REM is about 6 times slower than ::
(tested on Win7SP1 with 100000 comment lines).
For a normal usage it's not important (58µs versus 360µs per comment line)
Comments with ::
A ::
always executes a line end caret.
:: This is also a comment^
echo This line is also a comment
Labels and also the comment label ::
have a special logic in parenthesis blocks.
They span always two lines SO: goto command not working.
So they are not recommended for parenthesis blocks, as they are often the cause for syntax errors.
With ECHO ON
a REM
line is shown, but not a line commented with ::
Both can't really comment out the rest of the line, so a simple %~
will cause a syntax error.
REM This comment will result in an error %~ ...
But REM is able to stop the batch parser at an early phase, even before the special character phase is done.
@echo ON
REM This caret ^ is visible
You can use &REM or &:: to add a comment to the end of command line. This approach works because '&' introduces a new command on the same line.
Comments with percent signs %= comment =%
There exists a comment style with percent signs.
In reality these are variables but they are expanded to nothing.
But the advantage is that they can be placed in the same line, even without &
.
The equal sign ensures, that such a variable can't exists.
echo Mytest
set "var=3" %= This is a comment in the same line=%
The percent style is recommended for batch macros, as it doesn't change the runtime behaviour, as the comment will be removed when the macro is defined.
set $test=(%\n%
%=Start of code=% ^
echo myMacro%\n%
)
Performance REM
vs ::
vs %= =%
In short:
-
::
and%= =%
seems to have the same performance -
REM
takes ~ 50% more time than::
- In blocks, especially loops only
REM
consumes time, but::
is removed from the cached block when the block is parsed, therefore it consumes no time
For more info see SO: Question about Comments in Batch *.bat files and speed
Solution 3
Another alternative is to express the comment as a variable expansion that always expands to nothing.
Variable names cannot contain =
, except for undocumented dynamic variables like
%=ExitCode%
and %=C:%
. No variable name can ever contain an =
after the 1st position. So I sometimes use the following to include comments within a parenthesized block:
::This comment hack is not always safe within parentheses.
(
%= This comment hack is always safe, even within parentheses =%
)
It is also a good method for incorporating in-line comments
dir junk >nul 2>&1 && %= If found =% echo found || %= else =% echo not found
The leading =
is not necessary, but I like if for the symmetry.
There are two restrictions:
1) the comment cannot contain %
2) the comment cannot contain :
Solution 4
This answer attempts a pragmatic summary of the many great answers on this page:
jeb's great answer deserves special mention, because it really goes in-depth and covers many edge cases.
Notably, he points out that a misconstructed variable/parameter reference such as %~
can break any of the solutions below - including REM
lines.
Whole-line comments - the only directly supported style:
REM
(or case variations thereof) is the only official comment construct, and is the safest choice - see Joey's helpful answer.-
::
is a (widely used) hack, which has pros and cons:-
Pros:
- Visual distinctiveness and, possibly, ease of typing.
- Speed, although that will probably rarely matter - see jeb's great answer and Rob van der Woude's excellent blog post.
-
Cons:
-
Inside
(...)
blocks,::
can break the command, and the rules for safe use are restrictive and not easy to remember - see below.
-
Inside
-
If you do want to use ::
, you have these choices:
-
Either: To be safe, make an exception inside
(...)
blocks and useREM
there, or do not place comments inside(...)
altogether. -
Or: Memorize the painfully restrictive rules for safe use of
::
inside(...)
, which are summarized in the following snippet:
@echo off
for %%i in ("dummy loop") do (
:: This works: ONE comment line only, followed by a DIFFERENT, NONBLANK line.
date /t
REM If you followed a :: line directly with another one, the *2nd* one
REM would generate a spurious "The system cannot find the drive specified."
REM error message and potentially execute commands inside the comment.
REM In the following - commented-out - example, file "out.txt" would be
REM created (as an empty file), and the ECHO command would execute.
REM :: 1st line
REM :: 2nd line > out.txt & echo HERE
REM NOTE: If :: were used in the 2 cases explained below, the FOR statement
REM would *break altogether*, reporting:
REM 1st case: "The syntax of the command is incorrect."
REM 2nd case: ") was unexpected at this time."
REM Because the next line is *blank*, :: would NOT work here.
REM Because this is the *last line* in the block, :: would NOT work here.
)
Emulation of other comment styles - inline and multi-line:
Note that none of these styles are directly supported by the batch language, but can be emulated.
Inline comments:
* The code snippets below use ver
as a stand-in for an arbitrary command, so as to facilitate experimentation.
* To make SET
commands work correctly with inline comments, double-quote the name=value
part; e.g., SET "foo=bar"
.[1]
In this context we can distinguish two subtypes:
-
EOL comments ([to-the-]end-of-line), which can be placed after a command, and invariably extend to the end of the line (again, courtesy of jeb's answer):
-
ver & REM <comment>
takes advantage of the fact thatREM
is a valid command and&
can be used to place an additional command after an existing one. -
ver & :: <comment>
works too, but is really only usable outside of(...)
blocks, because its safe use there is even more limited than using::
standalone.
-
-
Intra-line comments, which be placed between multiple commands on a line or ideally even inside of a given command.
Intra-line comments are the most flexible (single-line) form and can by definition also be used as EOL comments.ver & REM^. ^<comment^> & ver
allows inserting a comment between commands (again, courtesy of jeb's answer), but note how<
and>
needed to be^
-escaped, because the following chars. cannot be used as-is:< > |
(whereas unescaped&
or&&
or||
start the next command).%= <comment> =%
, as detailed in dbenham's great answer, is the most flexible form, because it can be placed inside a command (among the arguments).
It takes advantage of variable-expansion syntax in a way that ensures that the expression always expands to the empty string - as long as the comment text contains neither%
nor:
LikeREM
,%= <comment> =%
works well both outside and inside(...)
blocks, but it is more visually distinctive; the only down-sides are that it is harder to type, easier to get wrong syntactically, and not widely known, which can hinder understanding of source code that uses the technique.
Multi-line (whole-line block) comments:
James K's answer shows how to use a
goto
statement and a label to delimit a multi-line comment of arbitrary length and content (which in his case he uses to store usage information).Zee's answer shows how to use a "null label" to create a multi-line comment, although care must be taken to terminate all interior lines with
^
.Rob van der Woude's blog post mentions another somewhat obscure option that allows you to end a file with an arbitrary number of comment lines: An opening
(
only causes everything that comes after to be ignored, as long as it doesn't contain a ( non-^
-escaped))
, i.e., as long as the block is not closed.
[1] Using SET "foo=bar"
to define variables - i.e., putting double quotes around the name and =
and the value combined - is necessary in commands such as SET "foo=bar" & REM Set foo to bar.
, so as to ensure that what follows the intended variable value (up to the next command, in this case a single space) doesn't accidentally become part of it.
(As an aside: SET foo="bar"
would not only not avoid the problem, it would make the double quotes part of the value).
Note that this problem is inherent to SET
and even applies to accidental trailing whitespace following the value, so it is advisable to always use the SET "foo=bar"
approach.
Solution 5
After I realized that I could use label ::
to make comments and comment out code REM
just looked plain ugly to me. As has been mentioned the double-colon can cause problems when used inside ()
blocked code, but I've discovered a work-around by alternating between the labels ::
and :
space
:: This, of course, does
:: not cause errors.
(
:: But
: neither
:: does
: this.
)
It's not ugly like REM
, and actually adds a little style to your code.
So outside of code blocks I use ::
and inside them I alternate between ::
and :
.
By the way, for large hunks of comments, like in the header of your batch file, you can avoid special commands and characters completely by simply goto
ing over your comments. This let's you use any method or style of markup you want, despite that fact that if CMD
ever actually tried to processes those lines it'd throw a hissy.
@echo off
goto :TopOfCode
=======================================================================
COOLCODE.BAT
Useage:
COOLCODE [/?] | [ [/a][/c:[##][a][b][c]] INPUTFILE OUTPUTFILE ]
Switches:
/? - This menu
/a - Some option
/c:## - Where ## is which line number to begin the processing at.
:a - Some optional method of processing
:b - A third option for processing
:c - A forth option
INPUTFILE - The file to process.
OUTPUTFILE - Store results here.
Notes:
Bla bla bla.
:TopOfCode
CODE
.
.
.
Use what ever notation you wish *
's, @
's etc.
MikeFHay
UK-based software developer working primarily on back-end Java projects. https://github.com/MikeFHay
Updated on July 17, 2022Comments
-
MikeFHay almost 2 years
I've been writing some batch files, and I ran into this user guide, which has been quite informative. One thing it showed me was that lines can be commented not just with
REM
, but also with::
. It says:Comments in batch code can be made by using a double-colon, this is better than using the REM command because labels are processed before redirection symbols.
::<remark>
causes no problems butrem <remark>
produces errors.Why then, do most guides and examples I see use the
REM
command? Does::
work on all versions of Windows?-
Digger over 8 yearsJust for the record, I've seen problems when "REM" is used to comment out a line with redirection under Windows 98.
-
mklement0 over 7 yearsAs an aside, in line with @Digger's comment: The linked guide is for DOS (
command.exe
), notcmd.exe
, the NT command processor as found on Windows 2000 onward.rem <remark>
works just fine in the latter (since at least Windows XP), andREM
is the official constracnt and the safest choice overall; while::
has its advantages, it is ultimately a hack that is problematic inside(…)
blocks (as discussed in many answers here). -
T.Todua about 6 yearsPossible duplicate of How to "comment-out" (add comment) in a batch/cmd?
-
T.S about 6 yearsSo, what situation with REM causes errors exactly?
-
-
James K over 11 yearsLOL! Make it one oversized variable! Genius!
%=ExitCode%
? Neat. Learn something new every day! -
James K over 11 yearsYou imply that the trailing
=
is necessary. But it does not seem to be. -
dbenham over 11 years@JamesK - I use the trailing
=
so that something like %=ExitCode=% is a "comment" and not a dynamic variable. I prefer to use a style that always works (except for limitations noted at bottom of answer of course). -
hoang almost 11 yearsHow do you handle the
/?
switch to make it print this menu ? -
GL2014 almost 11 years@hoang setlocal ENABLEDELAYEDEXPANSION <NEWLINE> set var=%~1 <NEWLINE> echo first param is %1 <NEWLINE> IF !VAR!=="/?" ( GOTO USAGE ) <NEWLINE> :USAGE <NEWLINE> echo blah blah.. <NEWLINE>
-
Admin about 10 yearsAlternating single and double colons must be a headache when you insert or delete a row.
-
LastStar007 almost 9 yearsIt should be noted that
%=
comments are finicky with quotation marks, i.e.set foo=bar %=baz
results infoo
expanding tobar %=baz
, as doesset foo="bar" %=baz
, whereas onlyset "foo=bar" %=baz
results infoo
expanding tobar
as intended. -
GreenAsJade over 8 yearsYou should summarize the contents of links provided in answers. Otherwise it's called a "link only answer", and is completely useless if the link disappears. In this case, the page pointed to is rather humorous in that it makes its choice based on optimising reading speed of batch files from slow floppy disk :)
-
jeb over 8 yearsThis is true, at least for Win7SP1,
::
can be 6 times faster thanREM
-
Rich almost 8 years@Firedan: Is the name of the batch file and its location relevant (along with the name and location of the file to redirect to?). Otherwise it'd be nice to simplify the example.
-
makoshichi almost 8 yearsNice touch adding a tl;dr
-
Scott Chu almost 8 yearsIf there's delayed variable usage in line, :: will cause some error messages, e.g. Can not find specificed disk driver..... So better use REM then.
-
mosh over 7 years:: comments are parsed, and special characters like > | end the comment, and the following text is not commented.
-
mklement0 over 7 years@LastStar007: Always using quoting style
set "foo=bar"
is worth recommending in general, because it is the most robust form that clearly delimits the value. The issue you're describing is inherent inset
's behavior, and not specific to%= … =%
comments: unless you use"var=val"
quoting,set
considers everything that follows the=
the value, including trailing whitespace (through the end of the line or, if applicable, the start of the next inline command). -
Aisah Hamzah over 6 years@mosh is right. For instance,
%VAR%
variables are expanded. Suppose you have (wrongly)set TARGET=C:\Program Files (x86)\"foo.exe"
, and inside aDO(..)
expression you have:: echo %TARGET%
you will get an error because the(x86)
gets expanded before the whole expression gets evaluated, leading to an invalidDO(..)
expression and very inexplicable errors (in this case "\Microsoft was unexpected at this time"). You don't even need|
or>
in your expression. A::
is not a real comment,REM
is, though. -
Sinjai over 6 yearsCame here getting all kinds of errors from my batch script. Changed all of my
::
comments toREM
, everything started working. Was not aware::
was a hack! -
Kieron Hardy about 6 yearsSee stackoverflow.com/a/20169219/1689714 for an exploration of the dynamic variables (e.g. %=ExitCode% %=ExitCodeAscii% %=C:% %=D:% %__CD__% etc.), what they mean, how they are set, etc..
-
Tim Sparkles about 6 years@GL2014 basically you're saying "you don't print this menu". Your example code requires prefixing echo to each line of the usage notes. James K's answer is misleading to the extent that it suggests there is some way to print the usage notes as written .
-
cdlvcdlv almost 6 years@Timbo I wrote a subroutine (
:PrintHelp
) for this answer that indeed does what @hoang asks for. I use <HELP> and </HELP> as markers but you can use whatever suits you. -
Serge Wautier about 3 yearsUpvoted for mentioning %= comment =%. OK, I read the comments. Will use with care...
-
EvgenKo423 almost 2 yearsIn blocks, especially loops only
REM
consumes time, but::
is removed from the cached block when the block is parsed, therefore it consumes no time – probably not, otherwise it wouldn't cause errors like this.