我应该在批处理文件中使用哪种评论样式?

时间:2012-09-13 13:49:11

标签: batch-file coding-style comments

我一直在写一些批处理文件,然后我遇到了this user guide,它提供了很多信息。它向我展示的一件事是,行不仅可以使用REM进行评论,还可以使用::进行评论。它说:

  

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

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

10 个答案:

答案 0 :(得分:329)

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的转义标签。

答案 1 :(得分:151)

评论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.batREM;.batREM^;<space>Comment 的问题,只应使用修改后的版本。

;

对于角色;,:\/=,也允许其中一个::

REM比:: <强>慢6倍(在带有100000条评论行的Win7SP1上测试)。
对于正常使用而言,它并不重要(58μs与每条评论线的360μs)

使用::

注释

:: This is also a comment^ echo This line is also a comment 始终执行行结尾插入符号。

::

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

显示REM时会显示::行,但不会显示评论为%~的行

两者都无法真正注释掉该行的其余部分,因此简单的REM This comment will result in an error %~ ... 将导致语法错误。

@echo ON
REM This caret ^ is visible

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

&

You can use&amp; REM或&amp; ::在命令行末尾添加注释。 这种方法有效,因为'&amp;'在同一行引入了一个新命令。

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

存在带百分号的评论样式。

实际上这些是变量,但它们被扩展为无 但优点是它们可以放在同一行,即使没有echo Mytest set "var=3" %= This is a comment in the same line=% 等号确保这样的变量不存在。

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

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

{{1}}

答案 2 :(得分:25)

另一种选择是将评论表达为变量扩展,它总是扩展为空。

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

答案 3 :(得分:24)

在我意识到我可以使用标签::来发表评论并注释掉代码REM时,我看起来很丑陋。如前所述,在()阻止代码中使用双冒号可能会导致问题,但我发现通过在标签::: 之间交替进行解决方法空间

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

使用您希望的*@等符号。

答案 4 :(得分:17)

此回答尝试在此页面上的许多优秀答案的实用摘要

jeb's great answer值得特别提及,因为它确实深入并涵盖了许多优势案例。
值得注意的是,他指出错误构造的变量/参数引用(例如%~)可能会破坏以下解决方案的任何 - 包括REM。< / SUP>

全行评论 - 唯一直接支持的风格:

  • REM (或其案例变体)是唯一的官方评论构建,是最安全的选择 - 请参阅Joey's helpful answer

  • ::是一个(广泛使用的) hack ,其利弊

    • <强>赞成

    • <强>缺点

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

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

  • 要么:为了安全起见,请在(...)块内部设置例外并在其中使用REM,或者不要将评论放在 {{ 1}}完全。
  • :记住在(...) 中安全使用::痛苦限制性规则,这些规则在以下代码段中进行了总结:
(...)

其他评论样式的模拟 - 内联和多行:

请注意,批处理语言不直接支持这些样式,但可以模拟

内联评论

*下面的代码片段使用@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 [1] 功能

在这种情况下,我们可以区分两种亚型:

  • EOL评论([to-the-] end-of-line),可以放在命令之后,并且总是延伸到行尾(再次,礼貌) of jeb's answer):

    • SET "foo=bar"利用ver & REM <comment>是有效命令的事实,REM可用于在现有命令之后添加其他命令。
    • &也适用,但实际上只能在ver & :: <comment>之外使用,因为它的安全使用比使用(...)独立版更加有限。
  • 内线注释位于行上的多个命令之间,或理想情况下甚至是内部的给定命令。
    内线注释是最灵活的(单线)形式,也可以用作EOL注释。

    • ::允许在命令之间插入评论 (同样,jeb's answer提供),但请注意{{1} }和ver & REM^. ^<comment^> & ver需要< - 转义,因为以下字符。不能按原样使用:> (而未转义的^< > |&启动 next 命令。 / p>

    • &&,详见dbenham's great answer最灵活的表单,因为可以放在里面命令(参数中)
      它以一种确保表达式始终扩展为空字符串 - 的方式利用变量扩展语法,只要注释文本既不包含||也不包含{{1 }}
      %= <comment> =%一样,%适用于:块的内部和内部,但它在视觉上更具特色;唯一的缺点是键入更难,语法更容易出错,而且不广为人知,这可能会妨碍对使用该技术的源代码的理解。

多行(整行块)评论

  • James K's answer展示了如何使用 REM语句和标签来划分任意长度和内容的多行注释(在他的情况下,他是用于存储使用信息。)

  • Zee's answer展示如何使用&#34; null标签&#34; 创建多行注释,但必须小心终止所有内线与%= <comment> =%

  • Rob van der Woude's blog post提到另一个有些模糊的选项,允许您 结束一个包含任意数量注释行的文件 < em>只打开(...) 会导致之后的所有内容被忽略,只要它不包含(非goto - 转义){{ 1}},即只要块不是关闭

[1]使用^定义变量 - 即在名称和(和值组合周围加上双引号 - 在命令中是必要的作为^,以确保跟随预期的变量值(直到下一个命令,在这种情况下是单个空格)不会意外地成为其中的一部分。
(顺便说一句:)不仅不会避免这个问题,它会使双引号成为值的一部分。)
请注意,此问题是SET "foo=bar"固有的问题,甚至适用于意外跟踪值后面的空格,所以建议始终使用{{ 1}}方法。

答案 5 :(得分:7)

This页面告诉您使用&#34; ::&#34;在某些限制下会更快 选择

时需要考虑的事情

答案 6 :(得分:4)

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

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

- &GT;我发现这样做的最好方法是防止解析器完整性失败,重用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^ 
)

答案 7 :(得分: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 ++的任何插件也是如此。

答案 8 :(得分:2)

有关该主题的非常详细的分析性讨论可在THIS页面

上找到

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

答案 9 :(得分:0)

批处理文件中有多种注释方式

1)使用rem

这是官方方式。尽管显然要在处理插入符号之前就停止解析,但执行显然比::花费的时间更长。百分比扩展发生在rem和::被识别之前,因此,如果存在百分比,则错误的百分比用法(即%~)将导致错误。在代码块中的任何地方都可以安全使用。

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

对于:: comment,':comment'是无效的标签名称,因为它开始带有无效字符。可以在标签中间使用冒号。如果空格始于标签的开头,则将其删除: label变为:label。如果标签中间出现空格或冒号,则不会解释名称的其余部分,这意味着如果有两个标签:f:oo:f rr,则两者都将被解释为{{1} },仅文件中后来定义的标签将被跳转到。标签的其余部分实际上是注释。 here列出了:f的多种选择。您永远不能::goto标签call::foogoto :foo不起作用。

它们在代码块之外可以正常工作,但是在代码块中的标签之后(无论是否有效),必须有一个有效的命令行。 goto ::foo确实是另一个有效命令。它将其解释为命令而不是标签。该命令具有优先权。这是CD到:: comment卷的命令,如果执行了::,该命令将起作用,否则将出现找不到卷的错误。这就是subst :: C:\之所以可以说更好的原因,因为它不能以这种方式解释,因此可以解释为标签,它是有效的命令。这不是递归的,即下一个标签不需要后面的命令。这就是为什么它们合二为一。

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

您也可以像这样在::注释中使用插入符号运算符:

::

但是出于上述原因,您需要结尾的@echo off echo hello ( :;(^ this^ is^ a^ comment^ ) :; ) :;^ this^ is^ a^ comment :; )

:;

只要有偶数就可以。毫无疑问,这是最好的注释方式-带有4行和@echo off ( echo hello :; :; comment :; comment :; ) echo hello 。使用:;,您不会遇到需要使用:;2> nul来消除的任何错误。您可以使用subst :: C:\使找不到卷的错误消失,但这意味着您还必须在代码中放入C:,以防止工作目录成为subst :: C:\

要在行尾发表评论,您可以执行 ::\command &::,但仍然必须是偶数,如下所示:

command & rem comment

第一个@echo off ( echo hello & :;yes echo hello & :;yes :; ) echo hello 在下一行有一个有效命令,但第二个echo hello & :;yes没有,因此它需要一个命令,即& :;yes

3)使用无效的环境变量

:;。在批处理文件中,未定义的环境变量将从脚本中删除。这样就可以在一行的末尾使用它们,而无需使用%= comment =%。通常使用无效的环境变量,即包含等号的环境变量。多余的相等不是必需的,但是使它看起来对称。同样,以“ =”开头的变量名称保留给未记录的动态变量。这些动态变量永远不会以“ =”结尾,因此通过在注释的开头和结尾使用“ =”,就不会发生名称冲突。注释不能包含&%

:

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

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

5)在文件末尾,未加括号的所有内容均为注释

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