如何在命令行中可靠地使用“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
有效,但我无法将 cmd
(文件/目录。名称完成)的/F
选项的链接,默认情况下该选项为ON?REM 的这种变体似乎是在评论部分启用&
符号的安全方法。
REM/
REM\
REM:
尽管有@dbenham 的评论,但我无法创建任何会与这些 REM 变体发生冲突的文件(我尝试了REM.bat
、REM;.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”而不忽略相邻命令?的主要内容,如果未能解决你的问题,请参考以下文章