我一直在写一些批处理文件,然后我看到了这个用户指南,它提供了很多信息。它告诉我的一件事是,行不仅可以用REM进行注释,还可以用::进行注释。它说:
批处理代码中的注释可以通过使用双冒号来生成,这比使用REM命令更好,因为标签在重定向符号之前被处理。::<remark>不会引起任何问题,但是rem <remark>会产生错误。
那么,为什么我看到的大多数指南和示例都使用REM命令呢?::适用于所有版本的Windows吗?
我一直在写一些批处理文件,然后我看到了这个用户指南,它提供了很多信息。它告诉我的一件事是,行不仅可以用REM进行注释,还可以用::进行注释。它说:
批处理代码中的注释可以通过使用双冒号来生成,这比使用REM命令更好,因为标签在重定向符号之前被处理。::<remark>不会引起任何问题,但是rem <remark>会产生错误。
那么,为什么我看到的大多数指南和示例都使用REM命令呢?::适用于所有版本的Windows吗?
当前回答
下面的回答试图对本页上许多很棒的答案进行实用主义的总结:
杰布的回答很好,值得特别提一下,因为它真的很深入,涵盖了许多边缘情况。 值得注意的是,他指出一个错误构造的变量/参数引用,比如%~,可以破坏下面的任何解——包括REM行。
全行注释——唯一直接支持的样式:
REM(或其大小写变体)是唯一的官方评论结构,也是最安全的选择——参见Joey的有用答案。 ::是一个(广泛使用的)黑客,它有优点和缺点: 优点: 视觉上的独特性,以及可能的打字便捷性。 速度,尽管这可能不太重要——看看jeb的精彩回答和Rob van der Woude的精彩博客文章。 缺点: 在(…)块内部,::可以破坏命令,安全使用的规则是限制性的,不容易记住-见下文。
如果你想使用::,你有这些选择:
或者:为了安全起见,在(…)块中创建一个异常并在那里使用REM,或者完全不在(…)块中放置注释。 或者:记住安全使用::inside(…)的痛苦的限制性规则,这些规则总结在下面的代码片段中:
@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.
)
模仿其他注释样式——内联和多行:
注意,批处理语言不直接支持这些样式,但是可以进行模拟。
内联注释:
*下面的代码片段使用ver作为任意命令的替身,以便于实验。 *要使SET命令在内联注释中正确工作,请双引号name=value部分;例如,SET "foo=bar".[1]
在这种情况下,我们可以区分两个子类型:
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 that REM 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 : Like REM, %= <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.
多行(全行块)注释:
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.
其他回答
REM评论
REM可以注释一个完整的行,也可以注释行尾的多行插入号,如果它不是第一个标记的结束的话。
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后面跟着一些字符。:\/=的工作方式有点不同,它不注释&号,所以你可以把它用作内联注释。
echo First & REM. This is a comment & echo second
但为了避免现有文件(如REM、REM.bat或REM;.bat)出现问题,应该只使用经过修改的版本。
REM^;<space>Comment
对于角色来说;也允许有;,:\/=
REM大约比::慢6倍(在Win7SP1上测试,有100000条注释行)。 对于正常使用来说,这并不重要(58µs vs 360µs /注释行)
评论:
A::总是执行行结束插入符。
:: This is also a comment^
echo This line is also a comment
标签和注释标签::在括号块中有一个特殊的逻辑。 它们总是跨越两行SO: goto命令不工作。 因此,不建议在括号块中使用它们,因为它们通常会导致语法错误。
使用ECHO ON显示REM行,但不显示注释为::
两者都不能真正注释掉该行的其余部分,因此简单的%~将导致语法错误。
REM This comment will result in an error %~ ...
但是REM能够在早期阶段停止批处理解析器,甚至在特殊字符阶段完成之前。
@echo ON
REM This caret ^ is visible
您可以使用& rem或&::在命令行末尾添加注释。 这种方法有效,因为'&'在同一行上引入了一个新命令。
带有百分号%= comment =%的注释
存在一个带有百分号的注释样式。
实际上,这些是变量,但它们被展开为零。 但优点是它们可以放在同一行中,即使没有&。 等号保证了这样一个变量不存在。
echo Mytest
set "var=3" %= This is a comment in the same line=%
对于批处理宏,建议使用百分比样式,因为它不会改变运行时行为,因为在定义宏时注释将被删除。
set $test=(%\n%
%=Start of code=% ^
echo myMacro%\n%
)
性能REM vs:: vs %= =%
简而言之:
::和%= =%似乎具有相同的性能 REM的时间比: 在块中,特别是循环中,只有REM消耗时间,但是::在解析块时从缓存块中删除,因此它不消耗时间
有关更多信息,请参阅SO:关于批处理*.bat文件中的注释和速度的问题
REM是在批处理文件中嵌入注释的有文档支持的方法。
::本质上是一个永远不能跳转到的空白标签,而REM是一个实际的命令,它什么也不做。在这两种情况下(至少在Windows 7上),重定向操作符的存在都不会导致问题。
然而,在某些情况下,::在块中表现不佳,不是作为标签而是作为某种驱动器号进行解析。我不太清楚具体在哪里,但仅此一点就足以让我只使用快速眼动。它是在批处理文件中嵌入注释并得到支持的方法,而::仅仅是特定实现的工件。
下面是一个例子,其中::在FOR循环中产生一个问题。
这个例子在桌面上的test.bat文件中不起作用:
@echo off
for /F "delims=" %%A in ('type C:\Users\%username%\Desktop\test.bat') do (
::echo hello>C:\Users\%username%\Desktop\text.txt
)
pause
虽然这个例子将正确地作为注释工作:
@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
问题似乎出现在试图将输出重定向到文件时。我的最佳猜测是,它将::解释为一个名为:echo的转义标签。
James K,我很抱歉我说错了很多。我所做的测试如下:
@ECHO OFF
(
:: But
: neither
:: does
: this
:: also.
)
这符合您对交替的描述,但失败于“)was unexpected at This time.”错误消息。
我今天做了一些进一步的测试,发现交替不是关键,但关键似乎是有偶数行,没有任何两行在一行以双冒号(::)开始,也没有双冒号结束。考虑以下几点:
@ECHO OFF
(
: But
: neither
: does
: this
: cause
: problems.
)
这个工作!
但还要考虑到这一点:
@ECHO OFF
(
: Test1
: Test2
: Test3
: Test4
: Test5
ECHO.
)
当以命令结尾时,注释数量为偶数的规则似乎并不适用。
不幸的是,这只是奇怪的足够,我不确定我想要使用它。
实际上,最好的解决方案,也是我能想到的最安全的解决方案是,如果一个像notepad++这样的程序将REM读取为双冒号,然后在保存文件时将双冒号写入REM语句。但我不知道这样一个程序,我也不知道任何notepad++的插件,这样做。
另一种替代方法是将注释表示为一个总是展开为零的变量展开。
变量名不能包含=,除了未记录的动态变量,比如 %=ExitCode%和%=C:%。任何变量名都不能在第一个位置后面包含=。所以我有时会使用下面的代码在括号内包含注释:
::This comment hack is not always safe within parentheses.
(
%= This comment hack is always safe, even within parentheses =%
)
它也是一种合并内联注释的好方法
dir junk >nul 2>&1 && %= If found =% echo found || %= else =% echo not found
前导=不是必须的,但我喜欢它的对称性。
有两个限制:
1)注释不能包含%
2)评论不能包含:
关于这个话题的一个非常详细和分析性的讨论可以在这个页面上找到
它有示例代码和不同选项的优点/缺点。