PowerShell:CLI 调用的转义规则
据我所知,当使用 -Command
选项从 cmd.exe
调用 PowerShell 时,转义规则本质上是 Linux 中使用的规则。因此,您使用反斜杠 (\
),而不是通常的反引号 (`
)。
这就是说,您不写:
C:\> powershell -c "echo `"That's a single quote: ' `""
而是
C:\> powershell -c "echo \"That's a single quote: ' \""
得到:
That's a single quote: '
这与您在 Linux 终端中键入的内容完全相同:
~ >>> bash -c "echo \"That's a single quote: ' \""
如果我没记错的话,此功能名为 PSNativeCommandArgumentPassing。 但比较在一定程度上是有效的。事实上,在 Linux 下,你可以写:
~ >>> bash -c "echo \"That's a double quote: \\\" \""
得到:
That's a double quote: "
而等效的 PowerShell 行:
C:\> powershell -c "echo \"That's a double quote: \\\" \""
给出
The string is missing the terminator: ".
通过反复试验,我意识到:
C:\> powershell -c "echo \"That's a double-quote: `"" \""
可以按预期工作。
你能向我解释一下`""
背后的逻辑是什么吗?
另外,从 powershell.exe
而不是 cmd.exe
调用 PowerShell 时,等效命令是什么?
As I have learned, when invoking PowerShell from cmd.exe
, with the -Command
option, escaping rules are essentially those used in Linux. So you use a backslash (\
), rather than the usual backtick (`
).
This is to say that you don't write:
C:\> powershell -c "echo `"That's a single quote: ' `""
but
C:\> powershell -c "echo \"That's a single quote: ' \""
to get:
That's a single quote: '
And this is the exact equivalent of what you would type in a Linux terminal:
~ >>> bash -c "echo \"That's a single quote: ' \""
If I am not wrong, this feature is named PSNativeCommandArgumentPassing.
But comparisons work up to a certain point. In fact, under Linux you write:
~ >>> bash -c "echo \"That's a double quote: \\\" \""
to get:
That's a double quote: "
while the equivalent PowerShell line:
C:\> powershell -c "echo \"That's a double quote: \\\" \""
gives
The string is missing the terminator: ".
By trial and error, I realised that:
C:\> powershell -c "echo \"That's a double-quote: `"" \""
works as expected.
Can you explain to me what is the logic behind: `""
?
Also, what are the equivalent commands when calling PowerShell from powershell.exe
, rather than cmd.exe
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
tl;dr
仅在 PowerShell 的命令行上,使用
\"
将"
传递到-c
(-Command
) 应该执行的代码。只有在生成的代码中,PowerShell 通常将
"
转义为`"
才适用,因此您可能必须组合两种转义技术:`\"
.`""
,具有相同的效果,但它不可靠。[1]\"
对于 PowerShell 自身的命令行解析来说,工作稳健,但可能会根据情况中断cmd.exe
端的调用 /em> - 请参阅底部部分以获取解决方法。从 PowerShell 调用 CLI(外部控制台应用程序)时,不仅会首先应用 PowerShell 自己的不同引用规则(支持
'...' 代码> 字符串,嵌入
"
内的"..."
转义为`"
),这是 PowerShell 7.2.x 之前长期存在的错误另外< /em> 需要转义"
字符。当嵌入外部程序参数时使用\
(仅);请参阅此答案。否;此功能 - 在 PowerShell 7.3 中成为正式功能(请参阅此答案) - 不会出现玩,因为:
它通常在您通过其 CLI 调用的旧版 Windows PowerShell 版本中不可用,
powershell.exe
(而现代的跨平台 PowerShell(核心) 版本的 CLI 是pwsh.exe
)它仅适用于来自 PowerShell 会话内部的调用。
它旨在解决从 PowerShell 调用带有嵌入式
"
或空字符串参数的外部程序时长期存在的问题 - 请参阅 这个答案。因此,链接的答案解决了您的最后问题:
此外,从
powershell.exe
(而不是cmd.exe
)调用 PowerShell 时的等效命令是什么?简而言之:不幸的是,至少在 PowerShell 7.2.x 之前,您必须另外手动使用
" 转义
嵌入外部程序参数(仅)。"
字符。为什么以下内容在
cmd.exe
中有效:PowerShell 仅将
\
识别为其命令行上的转义字符,< /strong> 与其他 CLI 保持一致。在 PowerShell 会话内,只有
`
(反引号) 用作转义字符。警告:虽然
\"
转义"
在两个 PowerShell 版本中均一致 >在PowerShell(命令行解析)方面,在某些情况下它可能会破坏cmd.exe
自己的解析 - 请参阅底部部分。当通过以下方式调用 PowerShell CLI 时
-c
(-Command
) 并执行一段 PowerShell 源代码,该代码(-c
后面的参数)被解析分两个阶段:"
字符都被剥离,其中转义的 (\"
)被保留且未转义。因此,PowerShell 最终执行的是逐字记录:
从上面可以看出为什么这不起作用:
PowerShell最终尝试逐字执行,
这是一个语法错误,因为在PowerShell内部会话
\
不转义"
-仅`"
或 - 在"..."
内,或者 -""
。从上面可以看出为什么这(大部分)有效:
""
有时,但并不总是作为\"
;[1] 这里就是这样 - 另见底部部分。结果,PowerShell 最终逐字执行以下命令,该命令有效,因为传递的转义
"
现在是`
-转义,因为它需要位于 PowerShell 内“...”
字符串:为了避免脆弱的
""
转义,最好通过组合所需的`
来制定此命令 -使用命令行转义\
-转义 - 即`\"
- 但请参阅底部部分以获得完全可靠的解决方案:避免
cmd 上的解析问题。 exe
端,\"
的安全替代品:而
\"
转义" 在两个 PowerShell 版本上一致地工作 PowerShell(命令行解析)端
,在某些情况下它可以破坏
cmd.exe
自己的解析相比之下,使用。从任务计划程序等无 shell 环境调用时,\"
是安全的。虽然有解决方法,但不幸的是,它们是 PowerShell 特定版本:
在 Windows PowerShell 中 (
powershell.exe)
"^""
(原文如此)代替\"
在PowerShell(核心)中(v6+,
pwsh.exe
)""
代替\"
重要提示:
-c
(-Command) 作为单个,
“...”
- 封闭参数。-c
(-Command
) 还接受多个参数 - 可以单独用双引号引起来或not - 在这种情况下,它只是在剥离未转义的"
之后连接这些参数,以形成要执行的代码。这种技术在某些情况下允许您摆脱\"
-逃脱(例如,powershell -c \"Between 2 & 3`\"\"
,但是(a)它需要你密切关注命令cmd.exe
的哪些部分将显示为未加引号,(b) 需要您^
转义任何cmd.exe
元字符,例如&,以及 (c)总是执行空白规范化,即将多个空格折叠成每个空格。
以下调用旨在逐字打印
Between 2 &
,演示一下:[1]
""
位于"..."
内的示例 不存在工作是powershell -c "echo \" Nat `""King`"" Cole \""
:它打印Nat "King",而不是
,即第二个转义的Nat "King" Cole
Cole"
丢失(但是,它在pwsh.exe
中可以正常工作,正如底部部分所述)。最终不值得猜测powershell.exe -c
如何准确地解析嵌入的""
序列,因为它显然不可靠,并且确实存在可靠的替代方案(\"
或者,来自cmd.exe
,也可"^""
)。tl;dr
On PowerShell's command line only, use
\"
to pass a"
through to the code that-c
(-Command
) should execute.Only in the resulting code does PowerShell's usual escaping of
"
as`"
apply, so you may have to combine the two escaping techniques:`\"
.`""
, had the same effect, but it doesn't work reliably.[1]\"
works robustly with respect to PowerShell's own parsing of its command line, but can situationally break calls on thecmd.exe
side - see the bottom section for workarounds.When calling CLIs (external console applications) from PowerShell, not only do PowerShell's own, different quoting rules apply first (support for
'...'
strings, embedded"
inside"..."
escaped as`"
), a long-standing bug up to PowerShell 7.2.x additionally requires escaping"
chars. with\
when embedded in external-program arguments (only); see this answer.No; this feature - which became official in PowerShell 7.3 (see this answer) - does not come into play, because:
it generally isn't (and won't be) available in the legacy Windows PowerShell edition that you're invoking via its CLI,
powershell.exe
(whereas the modern, cross-platform PowerShell (Core) edition's CLI ispwsh.exe
)it only applies to calls from inside a PowerShell session.
it is designed to address a long-standing problem when calling external programs with embedded
"
or empty-string string arguments from PowerShell - see this answer.Therefore, the linked answer addresses your last question:
In short: unfortunately, up to at least PowerShell 7.2.x you'll have to additionally, manually escape
"
chars. with"
embedded in external-program arguments (only).Why the following works from
cmd.exe
:PowerShell only recognizes
\
as an escape character on its command line, for consistency with other CLIs.Inside a PowerShell session, only
`
(backtick) serves as the escape character.Caveat: While
\"
to escape"
works consistently in both PowerShell editions on the PowerShell (command-line parsing) side, situationally it can breakcmd.exe
's own parsing - see the bottom section.When the PowerShell CLI is invoke via
-c
(-Command
) with a piece of PowerShell source code to execute, that code (the argument(s) following-c
is parsed in two stages:"
chars. are stripped, wheres escaped ones (\"
) are kept and unescaped.Therefore, what PowerShell ends up executing is verbatim:
From the above follows why this does not work:
PowerShell ends up trying to execute verbatim
which is a syntax error, because inside a PowerShell session
\
doesn't escape"
-only`"
or - inside"..."
, alternatively -""
do.From the above follows why this (mostly) works:
""
sometimes, but not always works as an alternative to\"
;[1] here it does - see also the bottom section.As a result, PowerShell ends up executing the following verbatim, which works, because the escaped
"
that was passed through is now`
-escaped, as it needs to be inside a PowerShell"..."
string:To avoid the brittle
""
escaping, it is better to formulate this command by combining the required`
-escaping with the command-line\
-escaping - i.e.`\"
- but see the bottom section for a fully robust solution:Avoiding parsing problems on the
cmd.exe
side, a safe alternative to\"
:While
\"
to escape"
works consistently in both PowerShell editions on the PowerShell (command-line parsing) side, situationally it can breakcmd.exe
's own parsing. By contrast, using\"
is safe when calling from no-shell environments such as Task Scheduler.While there are workarounds, they are, unfortunately PowerShell edition-specific:
In Windows PowerShell (
powershell.exe
)"^""
(sic) instead of\"
In PowerShell (Core) (v6+,
pwsh.exe
)""
instead of\"
Important:
These workarounds require that the whole code to pass to
-c
(-Command
) be passed as a single,"..."
-enclosed argument.-c
(-Command
) also accepts multiple arguments - which may individually be double-quoted or not - in which case it simply concatenates these arguments, after having stripped unescaped"
, to form the code to execute. This technique situationally allows you to get away with\"
-escaping (e.g.,powershell -c \"Between 2 & 3`\"\"
, but (a) it requires you to pay close attention to which parts of the commandcmd.exe
will see as unquoted, (b) would require you to^
-escape anycmd.exe
metacharacters such as&
in those parts, and (c) invariably performs whitespace normalization, i.e. folds runs of multiple spaces into a single one each.The following calls, designed to print verbatim
Between 2 & 3"
, demonstrate this:[1] An example of where
""
inside"..."
doesn't work ispowershell -c "echo \" Nat `""King`"" Cole \""
: instead ofNat "King" Cole
, it printsNat "King Cole
, i.e. the second escaped"
is missing (it would work fine inpwsh.exe
, however, as discussed in the bottom section). It's ultimately not worth speculating how, precisely, embedded""
sequences are parsed bypowershell.exe -c
, given that it demonstrably isn't reliable and that reliable alternatives do exist (\"
or, fromcmd.exe
, also"^""
).