更新:
tl;dr:
在Windows PowerShell和PowerShell (Core) v7.2.x之前的版本中,不幸的是,您必须手动\
转义嵌入在传递给外部程序的参数中的"
字符。
# From inside PowerShell:
# Note the outer '...' quoting and the unexpected need to escape
# the embedded " chars. as \" (unexpected, because PowerShell itself doesn't
# require " inside '...' to be escaped; also, PowerShell's escape char. is `).
# If outer "..." quoting must be used, use \`" (sic) to escape the embeded "
curl.exe -ku user@email:mypass -X PUT -d 'data={\"password\":\"keypass\"}' https://build.phonegap.com/api/v1/key
继续阅读以了解为什么这是必要的。
PowerShell的转义字符是`(所谓的反引号),因此为了在“…”(双引号,插值)字符串中嵌入“”字符,应该使用`"(或"")而不是\";相比之下,在'...'(单引号,逐字)字符串内部,不需要转义"。
在你的尝试中,PowerShell没有将\"视为转义的",因此看到了多个"..."字符串,最终当PowerShell在幕后必要时应用其按需重新引用时,传递了两个单独的字符串参数,它们分别不需要双引号,因为它们不包含空格,即:verbatim data={\和password:\keypass\}
根据
PowerShell的引用规则,你应该使用:
要么:
"data={`"password`":`"keypass`"}"
要么,更简单地,由于不需要字符串插值,通过一个逐字、单引号字符串,其中"字符不需要转义:
'data={"password":"keypass"}'
然而,遗憾的是,直到PowerShell 7.2.x,这还不够;请继续阅读详细信息。
在PowerShell 7.2.x之前,需要使用额外的转义层来转义嵌入的"字符,使用\转义调用(大多数)外部程序时:
在Windows PowerShell中,有一些边缘情况下,这种方法不起作用,这种情况下需要使用--%(参见下文)。特别是,将'"foo bar"'转义为'\"foo bar\"'不起作用,因为包围的\"位于字符串的开头和结尾-有关详细信息,请参阅
this answer。
此外,Windows上的一些外部程序只支持""转义(例如msiexec);对于这些程序,可以使用-replace '"', '""'来以编程方式执行额外的转义,假设值至少包含一个空格。对于根本不支持嵌入"字符的程序(WSH),也要这样做,以便嵌入的"至少不会破坏参数边界(但它们将被删除)。
对于期望\"转义的程序,使用以下-replace操作来以鲁棒的方式以编程方式执行额外的转义:
'...' -replace '(\\*)"', '$1$1\"'
如果输入字符串不包含现有的verbatim \"序列,则可以简化为'...' -replace '"', '\"'
$passwd = 'foo'
curl.exe -ku user@email:mypass -X PUT -d (
"data={`"password`": `"$passwd`"}" -replace '(\\*)"', '$1$1\"'
) https://build.phonegap.com/api/v1/key
这不应该是必需的,但由于自 v1 以来的一个错误而没有修复,因为担心破坏向后兼容性 - 参见 this answer。
PowerShell v7.3 大部分修复了这个问题,但在 Windows 上有选择性例外。
一个 向后和向前兼容的辅助函数是来自Native
模块 (Install-Module Native
) 的ie
函数,它消除了额外转义的需要,在 Windows 上包含了高知名度的 CLIs 的重要适应性,并且即使修复已经完成,也将按预期工作:
ie curl.exe ... -d "data={`"password`": `"$passwd`"}" ...
)
使用--%
,即 停止解析符号,就像Keith Hill的回答中所示,是一个次优解决方法,它也不需要额外的 \
转义,然而:
--%
有固有的限制 - 参见GitHub 文档问题 #6149 - 在类 Unix 平台上几乎无用 - 参见 GitHub 文档问题 #4963。
- 在
--%
后面的参数中嵌入 PowerShell 的变量值的唯一 - 令人尴尬且产生副作用的 - 方法是 (a) 将它们定义为环境变量(例如,$env:passwd = 'foo'
),并且 (b) 引用这些变量时cmd.exe
风格的方式,即使在 Unix 上也是如此(例如,%passwd%
)。
一种替代方法 - 特别是如果您需要在调用中包含 PowerShell 变量或表达式的值 - 是通过单个参数调用 cmd /c
并包含整个命令行;为了方便引用,以下示例使用了一个here-string(请参见this answer底部部分了解 PowerShell 的字符串字面量):
cmd /c @'
curl.exe -ku user@email:mypass -X PUT -d "data={\"password\":"\keypass\"}" https://build.phonegap.com/api/v1/key
'@
"
不是必需的,虽然使用额外的\
转义是有效的,但它(a)不应该是必需的,而且(b)如果底层PowerShell问题得到修复,它将会中断,尽管这可能通过修复来缓解 - 目前(自PowerShell Core 7.2.0-preview.5以来)仅作为实验性功能PSNativeCommandArgumentPassing
可用,可能需要选择加入假定它成为正式功能。 - mklement0