tl;dr
调用 PowerShell CLI 时(powershell.exe 用于 Windows PowerShell,pwsh 用于跨平台 PowerShell [Core] 6+ 版):
powershell -Command "Compare-Object (Get-Content tex1.txt) (Get-Content tex2.txt) | Where-Object {$_.SideIndicator -eq '<='} | select inputobject | ft -hidetableheaders"
如果您确实需要使用嵌入式",请继续阅读。
eryksun 指出您的问题是您在整个"..." 字符串中缺少嵌入" 字符的转义。 这导致cmd.exe 看到多个 字符串,包括它认为 unquoted 的部分,这会导致 | 和 < 等特殊字符出现问题 - 它们永远不会到达 PowerShell。
嵌套来自cmd.exe的双引号字符串是一件棘手的事情:
- 要让
cmd.exe 开心,您需要加倍嵌入的" 字符。 ("")
- 另外,要让
powershell.exe 开心,你需要\-escape " 字符。
- 注意:Windows 上的跨平台版本 PowerShell [Core] 6+ 现在也接受
"" 本身,这是最可靠的选择。
通常,在从cmd.exe 调用时处理引用和转义参数是一种令人沮丧的体验,没有通用的解决方案,这与 Unix 世界不同。遗憾的是,即使在 Unix 世界中,PowerShell 也有其自身的挑战。[1]
简而言之:转义嵌入的" 字符。当调用 Windows PowerShell CLI,powershell.exe,从 cmd.exe 如下(对于 PowerShell (Core) 7+ CLI,pwsh.exe, "" 是可靠的选择):
-
在使用powershell.exe -Command 时使用"^""(原文如此),这很有效。
-
警告:
"^"" 不能调用其他程序。
- 这让您免于额外转义,如果您使用
\",这将是必要的
-
示例:
powershell -command " Write-Output "^""a & b"^"" " 产生 a & b,正如预期的那样,& 不需要转义。
-
如果您使用更简单的 - 和惯用的 - \",您可能需要执行额外的转义:具体来说,您 必须单独^-escape以下cmd.exe元字符在^内\"...\"运行:& | < > ^谢谢LotPings。
-
示例:
powershell -command " Write-Output \"a ^& b\" " 产生a & b;也就是说,& 需要用 ^ 转义。
-
此外,要处理%(以及enabledelayedexpansion、!)逐字,不幸的是,转义语法取决于您是否从命令行调用 或 批处理文件:从前者使用 %^USERNAME% (!^USERNAME),从后者使用 %%USERNAME%% (^!USERNAME^! / ^^!USERNAME^^! inside \"...\" 运行) -有关血腥细节,请参阅this answer。
不幸的是,cmd.exe 使用了 \" 是危险的,因为它几乎被所有程序(批处理文件除外)支持,如果不是这些额外的转义要求,使用它的命令行具有跨不同平台和外壳工作的潜力 - 除了从 PowerShell 调用 的显着例外,遗憾的是,需要额外的转义层并且 "..." 内的 " 必须被转义为\`"(原文如此);见this answer。
请参阅底部,了解通过避免使用嵌套的" 来缓解逃避痛苦的方法。
其他程序,包括 PowerShellCore:
-
just "" 用于用 Microsoft 编译器编译的程序,在 Windows 上也可以使用 Python em> 和 Node.js 以及 PowerShell Core (pwsh.exe)。
遗憾的是,这个强大的选项不适用于powershell.exe,即Windows PowerShell。
-
将\"用于具有 Unix 传统的程序,例如 Perl 和 Ruby - 伴随着上面讨论的逃避问题。
避免嵌入":
当您调用 PowerShell 的 CLI 时,您通常可以摆脱 不需要嵌入 双 引号:
把它们放在一起:
powershell -Command "Compare-Object (Get-Content tex1.txt) (Get-Content tex2.txt) | Where-Object {$_.SideIndicator -eq '<='} | select inputobject | ft -hidetableheaders"
请注意,我还删除了您的命令周围的 & { ... },因为它不是必需的。
[1] eryksun 如下所述:“这是 Windows 命令行不可避免的挫败感。每个程序都使用它想要的任何规则解析自己的命令行。所以命令行的语法不仅必须与 shell (CMD) 一起工作,而且还必须与管道中调用的所有程序一起工作。在 Unix 世界中,shell 将命令行解析为 argv 数组,因此通常您只需获得正确的语法即可制作 shell快乐。”
PowerShell Core 的问题,即使在 Unix 上,也源于它在传递参数之前如何在幕后重新引用参数 - 请参阅 this GitHub docs issue。