DOS批处理文件中的双冒号(::)是什么意思?

66

我找到了这个程序:web.archive.org: http://baiyunmanor.com/blog/work/get-current-date-time-in-dos-batch-file/

::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: This uses Windows Scripting Host to set variables
:: to the current date/time/day/day_number
:: for Win9x/ME/NT/W2K/XP etc
:: Thanks go to Todd Vargo for his scripting
::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off
set TmpFile=”%temp%.\tmp.vbs”
echo> %TmpFile% n=Now
echo>>%TmpFile% With WScript
echo>>%TmpFile% .Echo “set year=” + CStr(Year(n))
echo>>%TmpFile% .Echo “set yr=” + Right(Year(n),2)
...
cscript //nologo “%temp%.\tmp.vbs” > “%temp%.\tmp.bat”
call “%temp%.\tmp.bat”
...
echo date F [ddmmyy] [%day%%month%%yr%]
:: datetime.bat

但我不知道这行是什么意思。

:: datetime.bat

在最后的意思是什么?


注意在被任务计划程序调用的批处理程序中不要使用 :: 作为 rem。当编写和测试批处理程序时,从命令提示符下它可以按预期工作,但是当从任务计划程序运行相同的程序时,会抛出错误:“if” 不是内部或外部命令、可执行的程序或批处理文件。 - user2954660
6个回答

86

::是一个标签(不准确地称为注释标签),在实践中,可以像REM一样被视为注释,因为它是一个“无法跳转”的标签。

然而,REM::之间有一些区别。主要的区别如下:

  • 使用ECHO ON命令会显示REM行,但不会显示用::注释的行。

  • ::可以执行行结束符(也就是,以::开头的一行末尾带有^符号,则下一行也是一条注释):

     :: This is a comment^
     echo but watch out because this line is a comment too
    
  • 标签和::有特殊的逻辑,在括号块中使用它们可能会导致问题 - 在( )内使用时要小心。例如:

     for %%D in (hi) do (
         echo Before...
         :: My comment
         :: Some other comment
         echo After...
     )
    

    输出:

     Before ...
     The system cannot find the drive specified.
     After...
    

10
当你引用 :: “也被称为注释标签” 时,应该包含一个链接到你得到那个引述的 官方 来源;否则你会有助于传播可能是错误的 _普遍看法_。 - Aacini
1
最重要的区别是括号块内部的特殊逻辑。如果您能提供更多相关信息的资源,那将非常棒。 - McK
4
块中的特殊处理在SO:goto命令不起作用中有描述,更多关于SO:我应该在批处理文件中使用哪种注释样式?的内容。 - jeb
2
哇,我在for循环中使用了::,花了一整天才找到这篇文章。在我的情况下,双冒号在()中的行为似乎是不确定的。如果它只是在for()中单独存在,它要么会导致执行崩溃,要么会显示“...无法找到指定的驱动器”(以此类推,不同的语言),而“chdir”清楚地显示了我的“cd”已经起作用。 - Sean

67

以双冒号开头的一行代表一个无效标签,命令处理器会忽略它,因此它可以用来插入注释。由于某些无法追溯的原因,许多人使用::在批处理文件中插入注释,但您必须注意,其使用中存在几个陷阱,这些陷阱在Koterpillar的回答中有所描述。看起来,使用::而非REM命令作为注释的第一次使用是为了在缓慢的机器(例如软盘)上加速批处理文件的执行,但这个理由已经不再成立。

任何包含无效标签的行都将被命令处理器忽略,您可以使用几乎任何特殊字符来生成无效标签。例如:

@echo off

:~ This is a comment
:` This is a comment
:! This is a comment
:@ This is a comment
:# This is a comment
:$ This is a comment
:% This is a comment
:^ This is a comment
:& This is a comment
:* This is a comment
:( This is a comment
:) This is a comment
:_ This is a comment
:- This is a comment
:+ This is a comment
:= This is a comment
:{ This is a comment
:} This is a comment
:[ This is a comment
:] This is a comment
:| This is a comment
:\ This is a comment
:: This is a comment
:; This is a comment
:" This is a comment
:' This is a comment
:< This is a comment
:> This is a comment
:, This is a comment
:. This is a comment
:? This is a comment
:/ This is a comment

echo OK

换句话说:如果想插入注释,但不想使用REM 命令(虽然我想不出为什么不用),那么您有32种可行的字符组合可以使用。 为什么要恰好使用这个:::?只是因为35年前编写的一些旧程序使用了吗?


1
你说得没错(几乎总是),但我不明白你为什么要列出这个列表?"~``!@#$%%*()_-{}[]\'.?/^&|<> 都是合法的标签,只有 +=,;:<space> 不能用作标签。 - jeb
10
既然您想不到原因,那我就给您两个:可读性(在批处理脚本中,:: 引人注目,因为它是大部分字母字符中的非字母字符……而且如果您来自C++,其中 // 是单行注释,那么 :: 也可以作为同样用途的注释)和 节省空间(如果您曾经遇到过脚本达到上限——超过60 kB——,您会感激能够节省一些字节……是的,也有很好的理由使用这样大的单体脚本)。 - 0xC0000022L
3
似乎你没有阅读我的帖子和评论。如果你想要可读性并且你来自C ++,那么使用://插入单行注释会更加合理!从这个角度来看,为什么不像VBScript中使用:'或像PowerShell和其他几种脚本语言中使用:#或者在SQL中使用:--或HTML中的:<--等等呢?换句话说:如果你想插入注释,并且有32种可能的字符组合可供选择,为什么你应该恰好选择::?选择::没有合理的原因。 - Aacini
8
@Aacini: 我已经读过了,这促使我评论。你提出的五种替代方案全部需要我比::更多地移动手指,更糟糕的是,其中三种使用超过两个字符。尽管这是一个逻辑上的解释,但我无法帮助解释"合理"或"可接受",因为这完全是主观的。但在这些替代选项中,如果我没有使用::的选项,那么://会是最可接受的选项之一。 - 0xC0000022L
4
使用 REM 命令时,如果像 REM /?a=1 这样的注释会导致错误(出现“此时未预期 1”错误)。而使用 :: 则可以很好地处理这些注释。 - genpfault
显示剩余2条评论

20

以冒号开头的行是一个标签,您可以使用 goto 跳转到该标签:

goto end
:end

以双冒号开头的行是标签,但您不能,甚至意外地跳转到它:

goto :end REM this doesn't work
::end

因此,双冒号用于注释掉行。
来源:http://www.robvanderwoude.com/comments.php

9
正如 acdcjunior 所提到的,标签和 :: 具有特殊逻辑,并且可能会在括号块中引起问题。
以下是几个示例:
示例 1
IF 1==1 (
  ::
)

样例1的输出结果

) was unexpected at this time.

示例2

IF 1==1 (
  ::
  ::
)

示例2的输出结果

The system cannot find the drive specified.

3
冒号(:)是标签标记,可以用于跳转指令。
有些人也将冒号(:)作为注释符号,因此双冒号只是一种样式化的REM语句。

1
如果您使用传统的REM命令在DOS批处理脚本中注释一行,则注释中的任何输出重定向仍将执行。例如,考虑以下脚本:
echo 1 > a.txt
rem echo 2 > b.txt
echo 3 > c.txt

即使该行被“注释掉”,此脚本仍将截断b.txt

使用无效的标签前缀(如双冒号)将禁用任何重定向。


1
抱歉,自MS-DOS6.22以来就不正确了。 REM甚至比标签注释更强。如果使用REM,解析器将停止解析该行,但对于标签则不会停止。 - jeb
@jeb:刚想起我可以在pcjs上尝试它。加载MS-DOS 6.22软盘,重新启动,退出设置,执行rem > a,然后dir a列出从此重定向创建的文件。 - ecm
正如所说,它可以在MS-DOS 6.22上运行(在虚拟机中进行了测试),但自那以后,“REM”不再重定向。这个问题是关于“cmd.exe”的。从前:你的答案正确的 :-) - jeb
1
你是对的,我错了,即使在Window98上,REM重定向仍然有效(也经过测试)。但我编辑了问题以使其更准确,因为示例代码至少需要Windows NT。 - jeb
1
@jeb:它不是期望“至少Windows NT”,而是旨在“适用于Win9x / ME / NT / W2K / XP”。在MS Windows 4.x(即95/98 / Me系列)中,批处理文件实际上是由DOS的command.com解释的,并且正如您测试的那样,此shell确实会在rem行上进行重定向。因此,即使没有理由优先使用MSW NT与cmd.exe::而不是rem,问题仍然包括“Win9x / ME”,在这里存在这种差异。 - ecm
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接