首页 > 解决方案 > Start-Process with PowerShell.exe 表现出嵌入单引号和双引号的不同行为

问题描述

首先,如果有人想知道我们为什么要以这种方式调用 PowerShell,我在构建的一个更复杂的命令中遇到了这种行为,但可以使用如下所示的更简单的示例来展示这种行为。在实践中,我们以管理员身份在 32 位 PowerShell 下运行命令,并在字符串中呈现附加变量(因此我不简单地使用单引号作为外部部分),但这似乎并没有考虑到下面的行为。


当我通过 调用 PowerShell 时,如果我在 PowerShell 可执行文件Start-Process的参数周围使用单引号,我会得到一些奇怪的行为。-Command例如:

Start-Process -FilePath Powershell.exe -ArgumentList "-Command 'ping google.com'"

只是呈现ping google.com为输出并退出。但是,如果我使用嵌套的双引号而不是单引号,如下所示:

Start-Process -FilePath Powershell.exe -ArgumentList "-Command `"ping google.com`""

ping运行并产生预期的输出:

使用 32 字节数据 ping google.com [173.194.78.113]:

来自 173.194.78.113 的回复:字节=32 时间=34ms TTL=45

来自 173.194.78.113 的回复:字节=32 时间=33ms TTL=45

来自 173.194.78.113 的回复:字节=32 时间=35ms TTL=45

来自 173.194.78.113 的回复:字节=32 时间=32ms TTL=45

173.194.78.113 的 Ping 统计信息:

数据包:发送 = 4,接收 = 4,丢失 = 0(丢失 0%),

大约以毫秒为单位的往返时间:

最小值 = 32 毫秒,最大值 = 35 毫秒,平均值 = 33 毫秒

-Command如果我对参数使用单引号而不是双引号,为什么命令字符串只是按原样呈现而不是执行?

标签: powershellargumentscommand-line-interfacequoting

解决方案


js2010 的有用答案是正确的,因为使用Start-Process是您的问题所附带的,并且该行为特定于 PowerShell 的CLI 对于powershell.exeWindows PowerShellPowerShell [Core] 6+):pwsh

在 Windows [1]上,需要考虑两层评估

  • (a) 将命令行初始解析为参数。

  • (b)由于使用 ( ) CLI 参数,将(空格连接的)结果参数评估为 PowerShell 代码。-Command-c

回复(一):

与 Windows 上的大多数控制台程序一样,PowerShell 仅识别"字符。(双引号) - 不也是'(单引号) - 具有句法功能。[2]

  • 也就是说,除非"字符。被转义,它们是在解析过程中被删除的字符串分隔符。

  • 正如上面所暗示的,'字符。不删除。

无论结果是什么参数 - 一个可能"被剥离的标记的数组 - 都与它们之间的单个空格连接起来,这成为 (b) 的输入。


为了在您的示例的上下文中解释这一点,请Start-Process从图片中删除:

注意:以下内容适用于调用自或涉及 shell 的cmd.exe任何上下文(包括Start-Process和 Windows 运行 ( WinKey-R) 对话框)。相比之下,如果需要, PowerShell会在后台重新引用命令行以始终使用 . "
换句话说:以下适用于PowerShell 所见的命令行。

引号命令:

# Note: This *would* work for calling ping if run from 
#       (a) PowerShell itself or (b) from a POSIX-like shell such as Bash.
#       However, via cmd.exe or any context where *no* shell is involved,
#       notably Start-Process and the Windows Run dialog, it does not.
powershell -Command 'ping google.com'
  • (a) 导致 PowerShell 找到以下两个逐字参数:'pinggoogle.com'

  • (b) 将这些逐字参数连接到表单'ping google.com'[2]作为 PowerShell 代码执行,因此输出此字符串文字的内容ping google.com

引号命令:

powershell -Command "ping google.com"
  • (a) 导致 PowerShell 剥离句法 "字符,找到以下单个逐字参数:ping google.com

  • (b) 然后导致这个逐字参数 -ping google.com作为 PowerShell 代码执行,因此导致命令调用,即ping带有参数的可执行文件google.com


[1] 在类 Unix 平台上,第一层不适用,因为被调用的程序只会看到一个逐字参数数组,而不是它们自己必须解析为参数的命令行。并不是说,如果您从类似 POSIX 的 shell(例如在类 Unix 平台上)调用 PowerShell CLI,则该 shell将单引号识别为字符串分隔符,并在PowerShell 看到它们之前将其剥离。bash

[2] 令人惊讶的是,在 Windows 上,最终由每个单独的程序来解释命令行,并且有些程序确实选择将其识别'为字符串分隔符(例如,Ruby)。但是,Windows 上的许多程序(包括 PowerShell 本身)都基于 C 运行时,它只能识别".

[3] 顺便说一句,请注意,这意味着正在发生空白规范化:也就是说,
powershell -Command 'ping google.com'同样会导致'ping google.com'.


推荐阅读