我一直在写一些批处理文件,我遇到了这个用户指南,它提供了很多信息。它向我展示的一件事是,不仅可以用 注释行REM
,还可以用::
. 它说:
批处理代码中的注释可以使用双冒号进行,这比使用 REM 命令更好,因为标签是在重定向符号之前处理的。
::<remark>
不会导致任何问题,但rem <remark>
会产生错误。
那么,为什么我看到的大多数指南和示例都使用该REM
命令?是否::
适用于所有版本的 Windows?
我一直在写一些批处理文件,我遇到了这个用户指南,它提供了很多信息。它向我展示的一件事是,不仅可以用 注释行REM
,还可以用::
. 它说:
批处理代码中的注释可以使用双冒号进行,这比使用 REM 命令更好,因为标签是在重定向符号之前处理的。
::<remark>
不会导致任何问题,但rem <remark>
会产生错误。
那么,为什么我看到的大多数指南和示例都使用该REM
命令?是否::
适用于所有版本的 Windows?
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
.
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
但是为了避免现有文件出现问题,例如REM
,REM.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 文件中的评论和速度的问题
另一种选择是将注释表示为始终扩展为空的变量扩展。
变量名称不能包含=
,除了未记录的动态变量,如
%=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)评论不能包含:
在我意识到我可以使用 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 等。
这个答案试图对这个页面上的许多很好的答案进行务实的总结:
jeb 的出色答案值得特别提及,因为它确实深入并涵盖了许多边缘情况。
值得注意的是,他指出错误构造的变量/参数引用%~
可能会破坏以下任何解决方案 - 包括REM
lines。
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"
方法。
此页面告诉在某些限制下使用“::”会更快只是选择时要考虑的事情
好问题......我也一直在寻找这个功能......
经过几次测试和技巧,似乎更好的解决方案是更明显的解决方案......
--> 我发现防止解析器完整性失败的最佳方法是重用 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^
)
詹姆斯 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++ 插件可以做到这一点。
此页面上提供了关于该主题的非常详细和分析性的讨论
它具有示例代码和不同选项的优缺点。
有多种方法可以在批处理文件中添加注释
1)使用 rem
这是官方的方式。::
尽管在处理插入符号之前它显然会提前停止解析,但它显然需要更长的时间来执行。百分比扩展发生在 rem 之前并被::
识别,因此不正确的百分比使用即%~
会导致错误,如果存在百分比。可以安全地在代码块中的任何地方使用。
2)使用标签:
等。::
:;
对于:: comment
, ':comment' 是无效的标签名称,因为它以无效字符开头。不过,可以在标签中间使用冒号。: label
如果空格从标签的开头开始,则将其删除为:label
。如果标签中间出现空格或冒号,则不解释名称的其余部分,这意味着如果有两个标签:f:oo
和:f rr
,则两者都将被解释为:f
并且仅跳转到文件中稍后定义的标签。标签的其余部分实际上是注释。这里::
列出了多种替代方法。你永远不能或一个标签。并且不会工作。goto
call
::foo
goto :foo
goto ::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