批处理字符转义

63

我相当熟练地编写Windows批处理脚本,但即使这些年来,如何正确转义字符仍让我感到困惑。特别是在尝试找出正确的转义正则表达式以供使用sed时更加困难。是否有任何工具可以帮助我?也许有一些工具可以让我粘贴一个“普通”字符串,然后输出该字符串的正确转义版本?

更新:我不愿给出示例,因为我不是在寻求如何转义一个特定字符串的答案。我也不是在寻求适用于一个特定应用程序的解决方案。我正在寻找一种工具,它可以帮助我获取每个需要转义的字符串的正确转义语法,无论哪个工具从命令行中消耗它。

话虽如此,我真正想要的正则表达式是

(^.*)(Form Product=")([^"]*") FormType="[^"]*" FormID="([0-9][0-9]*)".*$
拿到那个真正的regex(即就BATCH而言未被转义的)并将其包装在一些sed语法中,例如ssed "s@ --- Insert escaped regex here --- @http://psph/\1/\2@g" "%~1",最后对其进行转义... 有没有任何工具可以帮助转义任意字符串以供在BATCH命令行中使用?p.s. BATCH的转义语法有很多例外情况,我甚至会接受一个好的Cheat Sheet。

4
@Pacerier 我自1986年开始就一直在DOS等平台上编写批处理脚本,也写过汇编、C、C++等语言,然后转向Unix,现在不得不回到DOS。提问者所问的问题并不矛盾,下面的答案证明了这一点。批处理一直都是一门黑暗的艺术。 - Tom Harrison
4
要真正理解批处理转义,您必须吸收并理解cmd.exe批处理解析器的1、2、4、5、5.3和6阶段,这些阶段在https://dev59.com/6G855IYBdhLWcg3w5Igb#4095133中有描述。为了更好地理解,您还应该了解适用于命令行模式的微小差异。但这仅仅解释了cmd.exe本身及其所有内部命令的解析。每个外部命令可能都会有完全不同的附加转义规则。 - dbenham
密切相关:使用批处理回显特殊字符 - aschipfl
4个回答

88

正如dbhenham在这条评论中指出的那样,关于Windows命令解释器(CMD.EXE)如何解析脚本的更详细的答案可以在这个答案(最初由另一个用户jeb编写,由dbhenham进行了重大编辑和更新)中找到,该问题与此相关但更为普遍:

请注意,根据dbhenham的说法,这个答案是:

不正确、误导和不完整。

我认为这个答案对于几乎所有情况来说仍然足够好,但根据一个人确切的字符转义需求和这个答案的限制,可能需要仔细阅读上面的答案。

在作者的许可下,剩余部分已从Rob van der Woude's Scripting Pages site页面的Batch files - Escape Characters适应而来。

简短摘要

Windows(和DOS)批处理文件字符转义很复杂

就像宇宙一样,如果有人真正理解了批处理语言,那么这种语言将立即被一个更加奇怪和复杂的版本所替代。显然,这至少发生过一次 ;)

百分号 %

%可以转义为%% - "在双引号字符串中可能不总是需要[进行转义],只需尝试即可"

通常,使用插入符号 ^

以下字符“在双引号字符串中可能不需要进行转义,但这并不会有影响”:
- ^ - & - < - > - |
示例:使用echo a ^> b来在屏幕上打印a > b '“仅在FOR /F“subject”(即括号之间)中需要进行转义,除非使用backq`“仅在FOR /F“subject”(即括号之间)中需要进行转义,如果使用backq
以下字符“即使在双引号字符串中,也必须进行转义,仅在FOR /F“subject”(即括号之间)中需要进行转义”:
- ^
  • ,
  • ;
  • =
  • (
  • )

当使用延迟变量扩展时,双重转义感叹号

当延迟变量扩展处于活动状态时,! 必须转义为 ^^!

find搜索模式中使用双重双引号

"""

findstr正则表达式模式中使用反斜杠

  • \
  • [
  • ]
  • "
  • .
  • *
  • ?

同时

罗布通过电子邮件与我进行的进一步评论:

至于答案,恐怕混乱程度比原帖作者意识到的还要严重:括号转义的要求也取决于字符串是否在代码块内!

我想自动化工具可以在每个字符前插入一个符号,然后将所有百分号加倍 - 即使字符串是双引号也会失败!

此外,各个程序负责解析其命令行参数,因此某些转义所需的处理(例如 sedssed)可能是批处理脚本中调用的特定程序所需的。


5
我一直认为Rob Vanderwoude的网站是学习批处理的极佳参考资料,并且我已经阅读了其中许多部分,但不知何故我从未阅读过那个部分。感谢你指出它。 - HairOfTheDog
Rob的解释远胜于ss64.com。 - Pacerier
1
@PeterMortensen 你不需要转义空格,但是如果字符串中包含空格,则必须将其引用起来(否则它们会被解释为单独的字符串)。 - Kenny Evitt
@PeterMortensen - 这个答案 似乎涵盖了你想要做的事情。 - Kenny Evitt
3
虽然这是一个好的开始,但这个答案(以及Rob Van der Woud的网站)中有许多不正确、误导和不完整的陈述。要真正理解,请查看https://dev59.com/6G855IYBdhLWcg3w5Igb#4095133。 - dbenham
显示剩余4条评论

8

批处理中的转义字符是插入符(^)。如果您想在脚本中包含任何管道字符,您需要在字符前面加上插入符:

:: Won't work:
@echo Syntax: MyCommand > [file]

:: Will work:
@echo Syntax: MyCommand ^> [file]

1
是的,插入符号(caret)是我常用的转义字符,但在BATCH中它并不是唯一的转义字符。有时候转义字符是反斜杠,有时候是百分号,还有时候是双引号。你还没糊涂吧?还有更多。有时候转义字符是双百分号。偶尔它是插入符号和百分号的组合。看到我为什么在寻找辅助工具了吗? - HairOfTheDog
2
请问您能否举出一些在Windows BATCH中使用除插入符号以外的其他字符转义字符的例子? - Patrick Cuff
这里有一个例子 Patrick... 在这一行中,我同时使用了 ^ 和 '%%' echo if %%errorlevel%% neq 0 echo Problem moving [filename].txt ^>^> Log.txt >> some.bat 我在另一个批处理文件中将错误检查和报告写入了一个批处理文件中。在 %errorlevel% 前面的 ^ 不起作用,你需要使用 %%errorlevel%% 才能在新批处理文件中正确输出。 - iesou
1
@PatrickCuff,除了 >, <, &| 之外,还有哪些“管道字符”? - Pacerier

4
你可以简单地使用一个外部文件作为sed的输入。
或者在批处理中直接使用字符串,使用延迟扩展是个好主意。
setlocal DisableDelayedExpansion
set "regEx=s/^#*$/""/g"
setlocal EnableDelayedExpansion
sed !regEx! file.txt

编辑:如何在批处理中使用未修改的字符串

在此使用findstr从批处理程序中直接获取字符串并将其返回到结果变量中。
因此,您可以直接使用sed字符串。

@echo off
setlocal
REM SedString1#(^.*)(Form Product=")([^"]*") FormType="[^"]*" FormID="([0-9][0-9]*)".*$

call :GetSEDString result SedString1
setLocal EnableDelayedExpansion
echo the sedString is !result!
sed !result!
goto :eof

:GetSEDString <resultVar> <searchName>
:: Search the own batch file for <searchName> in a line with "REM <searchName>#"
:: Return all after the "#" without any modification
setLocal DisableDelayedExpansion
for /f "usebackq tokens=* delims=" %%G in (`findstr /n /c:"REM %~2#" "%~f0"`) do (
    set "str=%%G"
)
setLocal EnableDelayedExpansion
set "str=!str:*#=!"

for /F "delims=" %%A in ("!str!") DO (
  endlocal
  endlocal
  set "%~1=%%A"
  goto :eof
)

goto :eof

0
一个保留所有命令行参数的简单解决方案是使用%*:它返回整个命令行,从第一个命令行参数开始(在Windows NT 4中,%*还包括所有前导空格),并排除任何输出重定向。
例如,给定这个test.bat文件:
@echo off
echo Parameters are [%*] end params

如果你运行:test.bat qwe rt ":' *" ? (=),你将得到:参数是[qwe rt ":' *" ? (=)]结束参数

我注意到,经过4年多,这个答案仍然没有任何赞(截至本文撰写时)。你能否提供一个例子来解释你的意思? - RockPaperLz- Mask it or Casket

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