314

我一直在写一些批处理文件,我遇到了这个用户指南,它提供了很多信息。它向我展示的一件事是,不仅可以用 注释行REM,还可以用::. 它说:

批处理代码中的注释可以使用双冒号进行,这比使用 REM 命令更好,因为标签是在重定向符号之前处理的。::<remark>不会导致任何问题,但rem <remark>会产生错误。

那么,为什么我看到的大多数指南和示例都使用该REM命令?是否::适用于所有版本的 Windows?

4

10 回答 10

388

tl; dr: REM是在批处理文件中嵌入注释的记录和支持的方式。


::本质上是一个永远无法跳转到的空白标签,而REM实际上是一个什么都不做的命令。在这两种情况下(至少在 Windows 7 上),重定向运算符的存在都不会导致问题。

但是,::已知在某些情况下会在块中出现异常行为,不会被解析为标签,而是某种驱动器号。我对确切的位置有点模糊,但仅此一项就足以让我REM专门使用。这是在批处理文件中嵌入注释的记录和支持的方式,而::仅仅是特定实现的工件。


这是一个在循环中::产生问题的示例。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.

于 2012-09-13T13:56:18.510 回答
174

REM 的评论

AREM可以注释一个完整的行,如果它不是第一个标记的结尾,那么它也可以在行尾添加一个多行插入符号。

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

但是为了避免现有文件出现问题,例如REMREM.bat或者REM;.bat只应该使用修改过的变体。

REM^;<space>Comment

而对于字符;也是允许的之一;,:\/=

REM比(在 Win7SP1 上用 100000 条注释行测试)慢大约 6 倍。 对于正常使用,这并不重要(每条注释行 58µs 对 360µs)::

带有 :: 的评论

A::总是执行一个行结束插入符。

:: This is also a comment^
echo This line is also a comment

标签和注释标签 ::在括号块中有特殊的逻辑。
它们总是跨越两行SO: goto command not working
因此不建议将它们用于括号块,因为它们通常是语法错误的原因。

ECHO ON显示了一行REM,但没有注释的行::

两者都不能真正注释掉该行的其余部分,因此简单%~ 会导致语法错误。

REM This comment will result in an error %~ ...

但是 REM 能够在早期阶段停止批处理解析器,甚至在特殊字符阶段完成之前。

@echo ON
REM This caret ^ is visible

您可以使用&REM 或 &:: 在命令行末尾添加注释。这种方法之所以有效,是因为 '&' 在同一行引入了一个新命令。

带百分号的评论 %= 评论 =%

存在带有百分号的注释样式。

实际上,这些是变量,但它们被扩展为无。
但优点是它们可以放在同一行,即使没有&.
等号确保这样的变量不存在。

echo Mytest
set "var=3"     %= This is a comment in the same line=%

建议将百分比样式用于批处理宏,因为它不会改变运行时行为,因为在定义宏时注释将被删除。

set $test=(%\n%
%=Start of code=% ^
echo myMacro%\n%
)

性能REM对比::对比%= =%

简而言之:

  • ::并且%= =%似乎具有相同的性能
  • REM花费约 50% 的时间::
  • 在块中,特别是循环只REM消耗时间,但::在解析块时从缓存块中删除,因此 它不消耗时间

有关更多信息,请参阅SO:关于批 *.bat 文件中的评论和速度的问题

于 2012-09-13T14:02:00.030 回答
29

另一种选择是将注释表示为始终扩展为空的变量扩展。

变量名称不能包含=,除了未记录的动态变量,如
%=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)评论不能包含:

于 2012-09-13T16:49:30.100 回答
26

在我意识到我可以使用 label::来发表评论和注释掉代码之后,我觉得REM这很丑陋。如前所述,双冒号在()阻塞代码中使用时可能会导致问题,但我发现了一种通过在标签:::space

:: This, of course, does
:: not cause errors.

(
  :: But
   : neither
  :: does
   : this.
)

它不像 那样难看REM,实际上为您的代码添加了一点样式。

因此,在我使用的代码块之外,在它们内部,我在和::之间交替。:::

顺便说一句,对于大量注释,例如在批处理文件的标题中,您可以通过简单地goto覆盖您的注释来完全避免特殊命令和字符。这让你可以使用任何你想要的方法或风格的标记,尽管事实上如果CMD真的试图处理这些行它会抛出一个嘶嘶声。

@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
.
.
.

使用你希望的任何符号*' @s 等。

于 2012-09-17T09:43:55.713 回答
24

这个答案试图对这个页面上的许多很好的答案进行务实的总结:

jeb 的出色答案值得特别提及,因为它确实深入并涵盖了许多边缘情况。
值得注意的是,他指出错误构造的变量/参数引用%~可能会破坏以下任何解决方案 - 包括REMlines


整行注释——唯一直接支持的样式:

  • REM(或其案例变体)是唯一的官方评论结构,并且是最安全的选择- 请参阅Joey 的有用答案

  • ::是一个(广泛使用的)hack,它有优点也有缺点

    • 优点

    • 缺点

      • 内部(...)块,::可以破坏命令安全使用规则是限制性的,不容易记住- 见下文。

如果您确实想使用::,您有以下选择:

  • 要么:为了安全起见,在(...)块内创建一个异常并在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 注释([to-the-]end-of-line),可以放在命令之后,并且总是延伸到行尾(同样,由jeb 的回答提供):

    • ver & REM <comment>利用REM了有效命令这一事实,&可用于在现有命令之后放置附加命令。
    • ver & :: <comment>也可以,但实际上只能在(...)blocks::之外使用,因为它的安全使用比单独使用更受限制。
  • 行内注释,放置在一行上的多个命令之间,或者理想情况下甚至放在给定命令的内部。
    行内注释是最灵活的(单行)形式,根据定义也可以用作 EOL 注释。

    • ver & REM^. ^<comment^> & ver允许在命令之间插入注释(同样,由jeb 的回答提供),但请注意如何<以及>需要 -^转义,因为以下字符。不能按原样使用:(而未< > |转义&&&||启动下一个命令)。

    • %= <comment> =%,正如dbenham 的出色答案中所详述的那样,是最灵活的形式,因为它可以放在命令中(在参数中)
      它利用变量扩展语法的方式确保表达式始终扩展为空字符串——只要注释文本既不包含%也不:
      包含 Like REM,在块%= <comment> =%外部和内部都可以很好地工作(...),但它在视觉上更具特色;唯一的缺点是它更难输入,更容易在语法上出错,并且不广为人知,这可能会阻碍对使用该技术的源代码的理解。


多行(整行块)注释

  • James K 的回答显示了如何使用goto语句和标签来分隔任意长度和内容的多行注释(在他的情况下,他使用它来存储使用信息)。

  • Zee 的回答显示了如何使用“空标签”来创建多行注释,但必须注意使用^.

  • Rob van der Woude 的博客文章提到了另一个有点晦涩的选项,它允许您以任意数量的注释行结束文件:打开(只会导致后面的所有内容都被忽略,只要它不包含 (非^-escaped) ),即只要块没有关闭


[1]SET "foo=bar"用于定义变量 - 即在名称和组合=的值周围加上双引号- 在诸如 之类的命令中是必要的SET "foo=bar" & REM Set foo to bar.,以确保预期变量值之后的内容(在这种情况下直到下一个命令一个空格)不会意外地成为它的一部分。
(顺便说一句:SET foo="bar"不仅不会避免问题,还会使双引号成为 value 的一部分)。
请注意,此问题是固有的SET,甚至适用于值后面的意外尾随空格,因此建议始终使用该SET "foo=bar"方法。

于 2017-02-09T22:31:08.743 回答
7

页面告诉在某些限制下使用“::”会更快只是选择时要考虑的事情

于 2016-01-14T13:32:15.043 回答
4

好问题......我也一直在寻找这个功能......

经过几次测试和技巧,似乎更好的解决方案是更明显的解决方案......

--> 我发现防止解析器完整性失败的最佳方法是重用 REM:

echo this will show until the next REM &REM this will not show

您还可以使用带有“NULL LABEL”技巧的多行...(不要忘记行尾的 ^ 以保持连续性)

::(^
this is a multiline^
comment... inside a null label!^
dont forget the ^caret at the end-of-line^
to assure continuity of text^ 
)
于 2014-03-03T21:24:50.897 回答
3

詹姆斯 K,我很抱歉我所说的大部分内容都错了。我做的测试如下:

@ECHO OFF
(
  :: But
   : neither
  :: does
   : this
  :: also.
)

这符合您对交替的描述,但失败时出现“)在这个时候是出乎意料的。” 错误信息。

我今天做了一些进一步的测试,发现交替不是关键,但似乎关键是有偶数行,连续没有任何两行以双冒号 (::) 开头并且不以双冒号结尾. 考虑以下:

@ECHO OFF
(
   : But
   : neither
   : does
   : this
   : cause
   : problems.
)

这行得通!

但也要考虑这一点:

@ECHO OFF
(
   : Test1
   : Test2
   : Test3
   : Test4
   : Test5
   ECHO.
)

以命令结尾时,注释数为偶数的规则似乎并不适用。

不幸的是,这只是松鼠,我不确定我是否要使用它。

真的,最好的解决方案,我能想到的最安全的解决方案是,如果像 Notepad++ 这样的程序将 REM 读取为双冒号,然后在保存文件时将双冒号作为 REM 语句写回。但我不知道有这样的程序,也不知道有任何 Notepad++ 插件可以做到这一点。

于 2013-03-26T19:39:27.823 回答
2

页面上提供了关于该主题的非常详细和分析性的讨论

它具有示例代码和不同选项的优缺点。

于 2014-08-31T08:31:48.417 回答
1

有多种方法可以在批处理文件中添加注释

1)使用 rem

这是官方的方式。::尽管在处理插入符号之前它显然会提前停止解析,但它显然需要更长的时间来执行。百分比扩展发生在 rem 之前并被::识别,因此不正确的百分比使用即%~会导致错误,如果存在百分比。可以安全地在代码块中的任何地方使用。

2)使用标签:等。:::;

对于:: comment, ':comment' 是无效的标签名称,因为它以无效字符开头。不过,可以在标签中间使用冒号。: label如果空格从标签的开头开始,则将其删除为:label。如果标签中间出现空格或冒号,则不解释名称的其余部分,这意味着如果有两个标签:f:oo:f rr,则两者都将被解释为:f并且仅跳转到文件中稍后定义的标签。标签的其余部分实际上是注释。这里::列出了多种替代方法。你永远不能或一个标签。并且不会工作。gotocall::foogoto :foogoto ::foo

它们在代码块之外工作正常,但在代码块中的标签之后,无论是否无效,都必须有一个有效的命令行。:: comment确实是另一个有效的命令。它将其解释为命令而不是标签;该命令具有优先权。哪个是 cd 到::卷的命令,如果你已经执行,它将起作用subst :: C:\,否则你会得到一个找不到卷的错误。这就是为什么:;可以说更好,因为它不能以这种方式解释,因此被解释为一个标签,它作为有效命令。这不是递归的,即下一个标签不需要在它之后的命令。这就是他们成对出现的原因。

您需要在标签后提供有效命令,例如echo something. 代码块中的标签必须带有至少一个有效的命令,因此这些行是成对出现的。)如果下一行有空格或右括号,您将收到意外错误。如果两行之间有空格,::您将收到无效的语法错误。

您还可以在::评论中使用插入符号运算符,如下所示:

@echo off

echo hello
(
   :;(^
   this^
   is^
   a^
   comment^
   )
   :;
)
   :;^
   this^
   is^
   a^
   comment
   :;
) 

:;但是由于上述原因,您需要尾随。

@echo off

(
echo hello
:;
:; comment
:; comment
:;
)
echo hello

只要有偶数就可以了。这无疑是最好的注释方式——用 4 行和:;. :;这样您就不会遇到任何需要使用 or 来抑制的2> nul错误subst :: C:\。您可以使用subst :: C:\来使未找到卷错误消失,但这意味着您还必须将 C: 放入代码中以防止您的工作目录变为::\.

要在行尾添加注释,您可以使用 command &::or command & rem comment,但仍然必须是偶数,如下所示:

@echo off

(
echo hello & :;yes
echo hello & :;yes
:;
)

echo hello

echo hello & :;yes一个在下一行有一个有效的命令,但第二个& :;yes没有,所以它需要一个,即:;.

3)使用无效的环境变量

%= comment =%. 在批处理文件中,未定义的环境变量将从脚本中删除。这使得可以在行尾使用它们而不使用&. 习惯使用无效的环境变量,即包含等号的环境变量。额外的等号不是必需的,但使它看起来对称。此外,以“=”开头的变量名保留给未记录的动态变量。这些动态变量永远不会以“=”结尾,因此通过在注释的开头和结尾都使用“=”,就不会有名称冲突的可能性。评论不能包含%:

@echo off 
echo This is an example of an %= Inline Comment =% in the middle of a line.

4)作为命令,将stderr重定向到nul

@echo off
(
echo hello
;this is a comment 2> nul
;this is another comment  2> nul
)

5)在文件的末尾,未闭合括号后的所有内容都是注释

@echo off
(
echo hello
)

(this is a comment
this is a comment
this is a comment
于 2020-05-24T19:45:46.390 回答