如何在命令行中可靠地使用“rem”而不忽略相邻命令?

Posted

技术标签:

【中文标题】如何在命令行中可靠地使用“rem”而不忽略相邻命令?【英文标题】:How to reliably use `rem` within a command line without ignoring adjacent commands? 【发布时间】:2016-04-19 05:43:36 【问题描述】:

我正在尝试使用rem 命令在包含多个命令的命令行中添加注释。这里有一些例子来说明我的意思:

echo Hello & rem.Comment & echo world!

(echo Hello & rem.Comment) & echo world!

这工作得很好,每行中的两个echo 命令都按我的预期执行。 . 似乎修改了 rem 命令的行为,使其不会将剩余的行视为注释:

Hello 
world!

如果我放置了 SPACE(或任何其他分隔符 TAB,;=)而不是 .,则剩下的行,因此第二个echo 将被忽略(对于第二个示例,出现More? 提示,因为) 是注释的一部分,而cmd 期望关闭),因为() :

Hello 

我发现除了.,以下字符也可以使用::/\[]+。 其他工作是转义分隔符:^SPACE^TAB^,^;^=

不过,是否有安全可靠的方法来做到这一点?

我会很高兴有一个适用于命令提示符和批处理文件的解决方案。


根据this external reference,熟悉的语法echo.在某些情况下返回空行会失败,因此建议使用echo(,因为这是唯一可靠的方法。

但是,对于rem( 不起作用,rem( 之后的所有内容都不会被识别为命令。


由于我知道 Windows XP 中 rem 命令的一个奇怪错误(参考 this external link: rem %~),我对适用于 Windows Vista、Windows 7 或更高版本的解决方案感兴趣.

【问题讨论】:

从程序设计的角度来看,为什么要将内联注释放在代码中间而不是两端? @SomethingDark - 为什么不呢?内联注释可能很有用。 我通常使用 cmets 来解释代码的作用。在我写完我要评论的那一行之前这样做似乎很奇怪。 @SomethingDark - 但如果一行由连接的命令组成,这可能是完全合理的, 我删除了关于 rem %~ 问题的错误声明,因为它仅限于 Windows XP;所以对于rem 命令,cmd 可能没有更改... 【参考方案1】:

“奇怪”REM %~“错误”不仅限于 XP。它存在于使用 CMD.EXE 的所有现代版本的 Windows 中。阅读您的问题后,我wrote Simon of SS64 a note 澄清了这个问题。如果变量 var 存在并且你有 rem %var:=,则 REM 也会失败。

所以从技术上讲,盲目使用 REM 并不能保证安全。

但是,如果您愿意接受致命的 % 扩展风险,那么您列出的大多数 hack 都可以安全使用,但如果该行包含至少一个通过 & 的附加命令或&&.

如果存在名为REM(无扩展名)的文件,则在任何情况下都不能安全使用REM.

如果当前文件夹包含名为test.bat 的文件并且您使用REM\..\test.bat,则文件夹分隔符\/ 总是失败。

以类似的方式,REM:\..\test.bat 总是失败。

在类似的情况下,其他每一个 hack 都可能单独失败。例如,REM^[tab]\..\test.bat 单独失败,但如果与另一个命令连接则可以工作。这是我发现的唯一一种+[]^[tab] 可能失败的情况。

还有其他一些黑客可能会失败的情况。

如果 remC.bat 存在,则文件名中有效的集合 C(^[space]^,^;^=)中的任何字符都可能单独失败。例如,以下独立失败:

rem^  Fails if "rem .bat" exists

然而,当与另一个命令连接时,它们都是安全的:

echo OK&rem^  This is safe
rem^  This is safe &echo OK

临时更新

上面有些是错误的。正在http://www.dostips.com/forum/viewtopic.php?f=3&t=6895&p=44813#p44813 进行调查。

我相信以下是保证在所有情况下都能正常工作的最简单形式(忽略无效的 % 扩展)

REM: At least one space (or other token delimiter) must be after :
REM\ At least one space (or other token delimiter) must be after \
REM/ At least one space (or other token delimiter) must be after /
REM^[tab] At lease one space (or other token delimiter) must be after [tab]

但在尘埃落定之前,我不会更正之前的信息

结束临时更新


我最喜欢使用内联 cmets 的方法是使用不可能的变量。只有动态伪变量可以在名称中包含=,并且任何变量名称都不能包含两个=。所以我喜欢使用%= Remark goes here =%。这种形式的美妙之处在于它几乎可以在任何地方使用而不受惩罚,只要评论不包含%:。它甚至可以在带括号的代码块中安全使用。

for %%F in (*) do (
   %= Comment within code block     =%
   %= 2nd comment within code block =%
   FINDSTR /B %=Must match beginning of line=%  "string" %= Search string =%  "%%F" %= File to search =%
)

【讨论】:

编辑 - 对失败情况进行了重大更正 谢谢! %= =% 语法非常酷,但显然只适用于批处理文件;我正在为cmd 和批处理寻找“包罗万象”的解决方案,所以rem 似乎是唯一的方法...... @aschipfl - 我在 Win 10 上的测试显示,在独立使用时(没有 &),所有变体都可能失败。但是对于某些人来说,jeb 在 Win 7 上没有发现任何故障,我在工作时在我的 Win 7 上证实了他的发现。今晚回家后,我会仔细检查我的 Win 10 调查结果。 我很惊讶rem^<TAB> Comment 有效,但我无法将 放入文件名(但我很确定有一种方法,你也在 dostips 上提到过) ;无论如何,是否有指向cmd(文件/目录。名称完成)的/F选项的链接,默认情况下该选项为ON?【参考方案2】:

REM 的这种变体似乎是在评论部分启用& 符号的安全方法。

REM/
REM\
REM:

尽管有@dbenham 的评论,但我无法创建任何会与这些 REM 变体发生冲突的文件(我尝试了REM.batREM;.bat 等等)。 在REM^<char> 之后添加一个空格总是一个好主意。

%~ 的问题无法解决,因为 cmd.exe 对每一行使用多个解析器阶段。 并且%~ 错误是在早期阶段(百分比扩展阶段)检测到的,就在将检测到REM 的阶段之前。

但是,我更喜欢内联 cmets 的百分比 cmets,由 dbenham 描述

编辑: 我从REM^<char> 中删除了插入符号,因为这无关紧要。

通常REM 注释该行的其余部分,因为批处理解析器在解析器的第 2 阶段检测到 REM 关键字并切换到仅用于 REM 的专用解析器。

但是当一个字符被附加到REM时,关键字将不会在阶段2中被检测到。 如果字符是\/;,=+( 之一,解析器稍后将删除它并执行正常 REM 命令。

这就是为什么在这种情况下可以识别命令运算符&&&||| 的原因。

为什么rem/ | break 失败,但(REM/) | break 有效? 这是因为管道启动了两个单独的 cmd 子进程。 带括号的命令将在子进程中第一次解析。 但是没有括号,父进程已经解析了REM/并检查文件是否存在(但不执行)。 但是当这样的文件存在时,解析器足够聪明,可以删除分隔符并检测到REM 是一个内部命令。 这种行为看起来有点奇怪。

【讨论】:

所有黑客都容易受到\..\x.bat 技巧的影响。请参阅我修改后的答案。 再一次,你是对的,但我只是忘了提到你应该总是在REM^<char> 部分后面添加一个空格。并且附加\..\..\..\windows\system32\calc.exe 似乎只是REM^` and REM ^ 的问题:` 当 REM 单独使用时,我不明白添加额外的空间如何避免 \..\x.bat 问题。 您编辑的答案实际上就是我在我的回答中所说的,但不是那么简洁。我同意大多数使用多个命令。但是 REM^\ 由于\..\x.bat 导致单机失败 @aschipfl 我编辑了我的答案,我希望它现在已经完成了

以上是关于如何在命令行中可靠地使用“rem”而不忽略相邻命令?的主要内容,如果未能解决你的问题,请参考以下文章

如何在命令行中从脚本运行函数?

*忽略* C++和C#如何在命令行中显示百分比[重复]

如何在Linux的命令行中使用Evernote

从命令行卸载 MSI 文件而不使用 msiexec

如何忽略 Newman 中的 SSL 证书错误

Windows如何在cmd命令行中查看、修改、删除与添加、设置环境变量?