eplawless自己的答案可以简单有效地解决他的特定问题:它将替换"整个参数列表中的所有实例\",这就是Bash要求在双引号字符串中使用双引号表示的原因。
通常使用cmd.exe Windows命令行解释器(无论在命令行上还是经常错误地称为“ DOS提示符”-或在批处理文件中)回答如何在双引号字符串内转义双引号的问题:请参阅底部以了解PowerShell。
tl; dr:
您必须使用""合格的字符串时,以(另)一个批处理文件,您可以使用""与创建应用微软的C / C ++ / NET编译器。(它也接受\"),它在Windows 包括Python和Node.js的:
\"是许多其他程序(例如Ruby,Perl甚至Microsoft自己的Windows PowerShell(!))必需的 -唯一的选择,但是它的使用并不安全:
\"从外部传递字符串时,许多可执行文件和解释器都需要 -包括Windows PowerShell- 或(对于Microsoft的编译器而言)是替代的支持 -最终,由目标程序来解析参数列表。 ""
- 例:
foo.exe "We had 3\" of rain."
- 但是,使用
\"CAN可能会导致不必要的命令任意执行和/或输入/输出重定向:
- 以下字符存在此风险:
& | < >
- 例如,以下结果导致
ver命令的意外执行;有关说明,请参见下文,有关变通方法,请参见下一个要点:
foo.exe "3\" of snow" "& ver."
- 对于Windows PowerShell,
\""它"^""是健壮的,但替代品有限(请参见下面的“调用PowerShell的CLI ...”部分)。
如果您必须使用\",则只有3种安全的方法,但是这非常麻烦:向TS求助。
在批处理文件中使用(可能是选择性的)延迟变量扩展,可以将文字存储\"在变量中,并"..."使用!var!语法在字符串内引用该变量 -请参阅TS的帮助性答案。
- 上述方法,尽管是繁琐的,有可以应用它的优势有条不紊,它的工作原理强劲,与任一输入。
仅使用LITERAL字符串-不涉及变量的字符串-您会得到一种类似的系统方法:类别- ^转义所有 cmd.exe元字符: " & | < > -如果您也想抑制变量扩展- %:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
否则,您必须根据识别错误解释cmd.exe\"为结束定界符而认为字符串的哪些部分未被引用的公式来制定字符串:
有关背景信息,请继续阅读。
背景
注意:这是基于我自己的实验。让我知道我是否错了。
类似于POSIX的外壳(例如,类似Unix的系统上的Bash )在将参数分别传递到目标程序之前将参数列表(字符串)标记化:在其他扩展中,它们将参数列表拆分为单个单词(单词拆分),并从结果单词(引号删除)。目标程序被切换的阵列的个别参数,与句法引号除去。
相比之下,Windows命令解释器显然不会标记化参数列表,而只是传递包含所有参数(包括引号char)的单个字符串。-到目标程序。
但是,在将单个字符串传递给目标程序之前会进行一些预处理:^转义字符。除去双引号字符串之外的字符(它们转义以下字符),并首先插入变量引用(例如%USERNAME%)。
因此,与Unix中不同,目标程序负责解析以解析参数字符串并将其分解为带有引号的单个参数。因此,假设不同的程序可能要求使用不同的转义方法,并且没有一种保证可以与所有程序一起使用的转义机制-https : //stackoverflow.com/a/4094897/45375包含有关Windows命令行无政府状态的出色背景解析。
实际上,这\"是很常见的,但不是安全的,如上所述:
由于cmd.exe自身无法识别\"为转义的双引号,因此它可能会将命令行上的后续标记误解为未引号,并有可能将其解释为命令和/或输入/输出重定向。
概括地说:这个问题面,如果以下任意字符的遵循开口或不平衡 \":& | < > ; 例如:
foo.exe "3\" of snow" "& ver."
cmd.exe看到以下由错误解释\"为常规双引号引起的标记:
"3\"
of
snow" "
- 休息:
& ver.
由于cmd.exe认为& ver.是不带引号的,它解释为&(命令排序操作),然后执行的命令的名称(ver.-将.被忽略; ver报告cmd.exe的版本信息)。
总体效果是:
- 首先,
foo.exe仅使用前三个令牌调用。
- 然后,
ver执行命令。
即使在意外命令无害的情况下,由于并非所有参数都传递给您,所以您的总体命令也不会按设计工作。
许多编译器/解释器只能识别\" -例如,从中调用GNU C / C ++编译器,Python,Perl,Ruby,甚至是Microsoft自己的Windows PowerShell,cmd.exe并且,除了(有限制)使用的Windows PowerShell之外\"",因为它们没有简单的解决方案这个问题。
本质上,您必须事先知道命令行的哪些部分被误解为未引用,并有选择地- ^逃避& | < >这些部分中的所有实例。
相比之下,使用""是SAFE,但是遗憾的是仅基于Microsoft编译器的可执行文件和批处理文件(对于批处理文件,具有上述怪癖)支持该方法,值得注意的是不包括PowerShell-请参阅下一节。
从cmd.exe或类似于POSIX的外壳调用PowerShell的CLI :
注意:有关在 PowerShell中如何处理引用的信息,请参见底部。
从外部调用时(例如,cmd.exe从命令行或批处理文件从):
从 /批处理文件调用Windows PowerShell :cmd.exe
在类Unix平台(Linux,macOS)上,从类似POSIX的外壳调用PowerShell [Core]的CLI时,pwsh例如bash:
您必须使用\",但它既安全又保留空白:
$ pwsh -c " \"a& c|\".length" # OK: 5
相关信息
^只能用作未加引号的字符串中的转义字符 -在双引号的字符串中,^这不是特殊的,并视为文字。
- CAVEAT:传递给该语句的
^in参数的使用call已损坏(这适用于以下两种用法call:调用另一个批处理文件或二进制文件,并在同一批处理文件中调用子例程):
^用双引号括起来的实例会被莫名其妙地加倍,从而改变了传递的值:例如,如果变量%v%包含文字值a^b,则将(!)call :foo "%v%"赋给subroutine中的(第一个参数)。"a^^b"%1:foo
^with的无引号使用call已被完全破坏,因为^它不再可用于转义特殊字符:例如,至少在Windows上,甚至从未调用过call foo.cmd a^&b安静的中断(而不是传递文字(如没有的情况))-甚至从未被调用(!)。 7a&bfoo.cmdcallfoo.cmd
逸出一个文字%是一种特殊情况下,不幸的是,这需要根据是否在指定的字符串不同句法的命令行与一个批处理文件内 ; 参见https://stackoverflow.com/a/31420292/45375
- 简而言之:在批处理文件中,使用
%%。在命令行上,%不能转义,但是如果将a ^放在变量名的开头,结尾或内部,将其用引号引起来(例如echo %^foo%),则可以防止变量扩展(插值);%不属于变量引用的命令行实例被视为文字(例如100%)。
通常,为了安全地使用可能包含空格和特殊字符的变量值:
- 分配:包围两个变量的名称和在该值单一对双引号的 ; 例如,
set "v=a & b"将文字值分配a & b给变量%v%(相比之下,set v="a & b"将使双引号成为值的一部分)。将文字%实例转义为%%(仅在批处理文件中有效-参见上文)。
- Reference:双引号变量引用,以确保其值未插值;例如,
echo "%v%"不对值%v%进行插值和打印"a & b"(但请注意,双引号也总是打印)。相反,echo %v%将文字传递a给echo,将其解释&为命令排序操作符,因此尝试执行名为的命令b。
还要注意以上声明^与call语句的重用。
- 外部程序通常负责删除参数周围的双引号,但是,如前所述,在批处理文件中,您必须自己进行操作(例如,
%~1从第一个参数中删除双引号),可悲的是,没有直接我所知道的echo一种忠实地打印变量值而不用双引号引起来的方式。
- Neil提供了一个
for基于方法的解决方法,只要该值没有嵌入的双引号即可;例如:
set "var=^&')|;,%!"
for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe并不能识别单个 -quotes作为字符串分隔符-它们被视为文字和一般不能被用来与嵌入空白界定字符串; 同样,紧跟着单引号和它们之间的任何标记的标记被视为未标记,cmd.exe并据此进行解释。
- 但是,由于目标程序最终会执行自己的参数解析,因此某些程序(例如Ruby)即使在Windows上也可以识别单引号字符串。相比之下,C / C ++可执行文件,Perl和Python 无法识别它们。
但是,即使目标程序支持,也不建议使用单引号引起来的字符串,因为它们的内容不受可能引起的不必要的解释的保护cmd.exe。
在 PowerShell中引用:
Windows PowerShell是比Windows更高级的外壳程序cmd.exe,并且它已经成为Windows的一部分多年了(PowerShell Core也将PowerShell的经验也带到了macOS和Linux中)。
PowerShell 在引用方面在内部始终如一地工作:
- 在双引号字符串中,使用
`"或""转义双引号
- 在单引号字符串中,用于
''转义单引号
这在PowerShell命令行上以及从PowerShell 内部将参数传递给PowerShell脚本或函数时都有效。
(如上所述,将转义的双引号从外部传递到PowerShell 需要,\"或者更可靠地,\""-其他无效)。
可悲的是,当从PowerShell 调用外部程序时,您既需要适应PowerShell自己的报价规则,又需要针对目标程序进行转义:
这个有问题的行为也在此答案中进行了讨论和总结
双 -quotes内双 -quoted字符串:
考虑string "3`" of rain",PowerShell在内部将其转换为literal 3" of rain。
如果要将此字符串传递给外部程序,则除了 PowerShell 之外,还必须应用目标程序的转义。假设您要将字符串传递给C程序,该程序期望将嵌入式双引号转义为\":
foo.exe "3\`" of rain"
注意如何既 `" -使PowerShell的幸福- 和的\-使目标程序高兴-必须存在。
相同的逻辑适用于调用批处理文件,""必须在其中使用:
foo.bat "3`"`" of rain"
相比之下,嵌入单在-quotes 双 -quoted字符串需要在所有没有逃脱。
单内-quotes 单 -quoted字符串就不会需要额外的逃逸; 考虑'2'' of snow',这是PowerShell的表示形式2' of snow。
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShell将单引号字符串转换为双引号字符串,然后再将其传递给目标程序。
但是,单引号字符串内的双引号(对于PowerShell不需要转义)仍然需要为目标程序转义:
foo.exe '3\" of rain'
foo.bat '3"" of rain'
的PowerShell v3的推出了魔法--%选项,叫做停止解析符号,这减轻一些痛苦,通过传递东西后,不解释到目标程序,保存cmd.exe风格的环境变量引用(例如,%USERNAME%),这是扩大; 例如:
foo.exe --% "3\" of rain" -u %USERNAME%
注意如何逃避嵌入"作为\"目标程序只(不也为PowerShell的作为\`")就足够了。
但是,这种方法:
- 不允许转义
%字符以避免环境变量扩展。
- 禁止直接使用PowerShell变量和表达式;相反,必须首先在命令行中将命令行内置在字符串变量中,然后
Invoke-Expression在第二步中使用进行调用。
因此,尽管有很多进步,PowerShell在调用外部程序时并没有使转义变得容易得多。但是,它引入了对单引号字符串的支持。
我不知道,如果它基本上可以在Windows世界永远开关,放开的Unix模式的外壳做的所有标记化和引用的去除可以预见,在前面,不论目标程序,然后调用目标程序通过传递所产生的令牌。