PowerShell:CLI 调用的转义规则

发布于 2025-01-16 13:14:43 字数 1343 浏览 0 评论 0原文

据我所知,当使用 -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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏至、离别 2025-01-23 13:14:43

tl;dr

  • 仅在 PowerShell 的命令行上,使用 \"" 传递到-c (-Command) 应该执行的代码。

    • 只有在生成的代码中,PowerShell 通常将 " 转义为 `" 才适用,因此您可能必须组合两种转义技术:`\".

      • 您的尝试,`"",具有相同的效果,但它不可靠[1]
    • \" 对于 PowerShell 自身的命令行解析来说,工作稳健,但可能会根据情况中断 cmd.exe 端的调用 /em> - 请参阅底部部分以获取解决方法。




  • 从 PowerShell 调用 CLI(外部控制台应用程序)时,不仅会首先应用 PowerShell 自己的不同引用规则(支持 '...' 代码> 字符串,嵌入" 内的 "..." 转义为 `"),这是 PowerShell 7.2.x 之前长期存在的错误另外< /em> 需要转义 " 字符。当嵌入外部程序参数时使用 \ (仅);请参阅此答案



此功能名为PSNativeCommandArgumentPassing

否;此功能 - 在 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 -c "echo \"That's a single quote: ' \""
  • PowerShell 仅将 \ 识别为其命令行上的转义字符,< /strong> 与其他 CLI 保持一致。

    • 在 PowerShell 会话内,只有 `(反引号) 用作转义字符。

    • 警告:虽然 \" 转义 " 在两个 PowerShell 版本中均一致 >在PowerShell(命令行解析)方面,在某些情况下它可能会破坏cmd.exe自己的解析 - 请参阅底部部分。

  • 当通过以下方式调用 PowerShell CLI 时-c (-Command) 并执行一段 PowerShell 源代码,该代码(-c 后面的参数)被解析分两个阶段

    • 首先,所有未转义的 " 字符都被剥离,其中转义的 (\")被保留且未转义。
    • 只有然后才是解析结果并作为PowerShell代码执行

因此,PowerShell 最终执行的是逐字记录:

echo "That's a single quote: ' "

从上面可以看出为什么这不起作用

:: SYNTAX ERROR
powershell -c "echo \"That's a double quote: \\\"  \""

PowerShell最终尝试逐字执行,

echo "That's a double quote: \" "

这是一个语法错误,因为在PowerShell内部会话 \不转义 " -仅 `" 或 - 在 "..." 内,或者 - ""


从上面可以看出为什么这(大部分)有效:

:: Works, but not robustly
powershell -nop -c "echo \"That's a double-quote: `""  \""
  • ""有时,但并不总是作为 \";[1] 这里就是这样 - 另见底部部分。

  • 结果,PowerShell 最终逐字执行以下命令,该命令有效,因为传递的转义 " 现在是 `-转义,因为它需要位于 PowerShell 内“...”字符串:

     echo "这是一个双引号:`" "
    

为了避免脆弱的 "" 转义,最好通过组合所需的 ` 来制定此命令 -使用命令行转义\-转义 - 即 `\" - 但请参阅底部部分以获得完全可靠的解决方案:

powershell -nop -c "echo \"That's a double-quote: `\"  \""

避免 cmd 上的解析问题。 exe端,\"的安全替代品:

\"转义" 在两个 PowerShell 版本上一致地工作 PowerShell(命令行解析)端,在某些情况下它可以破坏cmd.exe自己的解析相比之下,使用。从任务计划程序等无 shell 环境调用时,\" 是安全的。

虽然有解决方法,但不幸的是,它们是 PowerShell 特定版本

  • 在 Windows PowerShell 中 (powershell.exe)

    • 使用"^""(原文如此)代替\"

  • PowerShell(核心)中(v6+,pwsh.exe

    • 使用 "" 代替 \"

重要提示:

  • < p>这些解决方法要求整个代码传递给-c-Command) 作为单个“...” - 封闭参数

  • -c (-Command) 还接受多个参数 - 可以单独用双引号引起来或not - 在这种情况下,它只是在剥离未转义的 " 之后连接这些参数,以形成要执行的代码。这种技术在某些情况下允许您摆脱 \"-逃脱(例如, powershell -c \"Between 2 & 3`\"\",但是(a)它需要你密切关注命令cmd.exe的哪些部分将显示为未加引号,(b) 需要您 ^ 转义任何 cmd.exe 元字符,例如 &,以及 (c)总是执行空白规范化,即将多个空格折叠成每个空格。


以下调用旨在逐字打印  Bet​​ween 2 &,演示一下:

:: BREAKS, because cmd.exe sees `&` as *outside a double-quoted string*
powershell -c " \" Between 2 & 3`\" \" "

:: PowerShell (Core) workaround
pwsh -c " "" Between 2 & 3`"" "" "

:: Windows PowerShell workaround
powershell -c " "^"" Between 2 & 3`"^"" "^"" "

[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: `\".

      • Your attempt, `"", 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 the cmd.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.


this feature is named PSNativeCommandArgumentPassing

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 is pwsh.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:

      • Also, what are the equivalent commands when calling PowerShell from powershell.exe, rather than cmd.exe?

    • 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 -c "echo \"That's a single quote: ' \""
  • 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 break cmd.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:

    • First, all unescaped " chars. are stripped, wheres escaped ones (\") are kept and unescaped.
    • Only then is the result parsed and execute as PowerShell code.

Therefore, what PowerShell ends up executing is verbatim:

echo "That's a single quote: ' "

From the above follows why this does not work:

:: SYNTAX ERROR
powershell -c "echo \"That's a double quote: \\\"  \""

PowerShell ends up trying to execute verbatim

echo "That's a double quote: \" "

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:

:: Works, but not robustly
powershell -nop -c "echo \"That's a double-quote: `""  \""
  • "" 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:

     echo "That's a double-quote: `"  "
    

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:

powershell -nop -c "echo \"That's a double-quote: `\"  \""

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 break cmd.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)

    • Use "^"" (sic) instead of \"
  • In PowerShell (Core) (v6+, pwsh.exe)

    • Use "" 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 command cmd.exe will see as unquoted, (b) would require you to ^-escape any cmd.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:

:: BREAKS, because cmd.exe sees `&` as *outside a double-quoted string*
powershell -c " \" Between 2 & 3`\" \" "

:: PowerShell (Core) workaround
pwsh -c " "" Between 2 & 3`"" "" "

:: Windows PowerShell workaround
powershell -c " "^"" Between 2 & 3`"^"" "^"" "

[1] An example of where "" inside "..." doesn't work is powershell -c "echo \" Nat `""King`"" Cole \"": instead of Nat "King" Cole, it prints Nat "King Cole, i.e. the second escaped " is missing (it would work fine in pwsh.exe, however, as discussed in the bottom section). It's ultimately not worth speculating how, precisely, embedded "" sequences are parsed by powershell.exe -c, given that it demonstrably isn't reliable and that reliable alternatives do exist (\" or, from cmd.exe, also "^"").

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文