带有管道的 powershell 和 cmd 的问题

cal*_*o31 1 powershell cmd

我有这个在 powershell 上运行正常的命令

Compare-Object (Get-Content "tex1.txt") (Get-Content "tex2.txt") | Where-Object{$_.SideIndicator -eq "<="} | select inputobject |  ft -hidetableheaders
Run Code Online (Sandbox Code Playgroud)

我正在尝试通过执行以下操作在 cmd 中运行:

powershell -Command " & {Compare-Object (Get-Content "tex1.txt") (Get-Content "tex2.txt") | Where-Object{$_.SideIndicator -eq "<="} | select inputobject |  ft -hidetableheaders}"
Run Code Online (Sandbox Code Playgroud)

但它说的是:名称、目录或卷语法不正确(是西班牙语,所以我不知道确切的翻译)

我认为问题在于管道,因为在管道之前运行所有内容:Compare-Object (Get-Content "tex1.txt") (Get-Content "tex2.txt")有效

PD:我也尝试^在管道之前写,但我没有成功。

mkl*_*nt0 5

tl;博士

调用 PowerShell CLI 时powershell.exe适用于Windows PowerShellpwsh适用于跨平台PowerShell [Core] 6+版):

  • 使用嵌入"到整个"..."字符串中会带来逃避挑战。

  • 如果对于给定的命令可行,那么在嵌入"情况下制定它是最简单的解决方案:

powershell -Command "Compare-Object (Get-Content tex1.txt) (Get-Content tex2.txt) | Where-Object {$_.SideIndicator -eq '<='} | select inputobject |  ft -hidetableheaders"
Run Code Online (Sandbox Code Playgroud)

继续阅读,如果您确实需要使用嵌入式".


eryksun指出您的问题是您缺乏对嵌入"字符的转义。在整个"..."字符串中,这会导致cmd.exe看到多个字符串,包括它认为未加引号的部分,这会导致特殊字符出现问题,例如|<- 它们永远不会到达PowerShell

嵌套双引号字符串cmd.exe是一件棘手的事情:

  • 为了cmd.exe开心,您需要将嵌入的字符加倍"。( "")
  • 另外,为了powershell.exe开心,你需要\-escape"字符。
    • 注意:PowerShell [Core] 6+,跨平台版本,在 Windows 上现在也可以""自己接受,这是最健壮的选择。

通常,与cmd.exeUnix 世界不同,在调用 from 时处理引用和转义参数是一种令人沮丧的体验,没有通用的解决方案。遗憾的是,即使在 Unix 世界中,PowerShell也有自己的挑战。[1]

简而言之:转义嵌入的"字符。调用Windows PowerShell CLI 时,powershell.exe,cmd.exe如下(对于PowerShell (Core) 7+ CLI,pwsh.exe""是可靠的选择):

  • 使用"^""使用(sic) powershell.exe -Command,它运行良好。

    • 警告"^"" 调用运行其他程序
    • 这使您免于额外的转义,如果您使用,这将是必要的\"
    • 示例powershell -command " Write-Output "^""a & b"^"" "yields a & b,正如预期的那样,并且&不需要转义。
  • 如果您使用更简单 - 和习惯 -\"可能需要执行额外的转义:具体来说,您必须单独 -^转义以下cmd.exe带有^内部\"...\"运行的元字符:& | < > ^谢谢,LotPings

    • 示例powershell -command " Write-Output \"a ^& b\" "产量a & b;也就是说,&需要转义^
  • 此外,要逐字处理%(并使用enabledelayedexpansion, !),转义语法不幸取决于您是从命令行还是批处理文件调用:前者使用( ) ,后者使用( /内部运行) - 请参阅这个关于血腥细节的答案%^USERNAME%!^USERNAME%%USERNAME%%^!USERNAME^!^^!USERNAME^^!\"...\"

不幸的是cmd.exe,使用了\"treacherous,因为几乎所有程序(批处理文件除外)都支持它,如果不是这些额外的转义要求,使用它的命令行有可能跨不同平台和shells - 除了从 PowerShell调用的显着例外,可悲的是,需要额外的转义层,并且"内部"..."必须转义为\`"(sic);看到这个答案

有关通过避免使用nested 来缓解逃避痛苦的方法,请参阅底部部分"


其他程序,包括 PowerShell Core

  • 使用只是 ""用于编译程序微软的编译器,并在Windows上,还的PythonNode.js的以及PowerShell的核心pwsh.exe
    遗憾的是,这个强大的选项并没有一起工作powershell.exe,即Windows PowerShell中

  • 使用\"与Unix的传统节目,如Perl和Ruby -附带逃逸头痛如上所述。


避免嵌入"

当您调用 PowerShell 的 CLI 时,您通常无需嵌入引号即可逃脱

  • 您的字符串中可能有一些根本不需要引用的参数,例如text1.txttext2.txt

  • 您也可以在整个命令字符串中使用引号 ( '...'),它不需要转义;请注意,从 PowerShell 的角度来看,此类字符串是字符串文字

把它们放在一起:

powershell -Command "Compare-Object (Get-Content tex1.txt) (Get-Content tex2.txt) | Where-Object {$_.SideIndicator -eq '<='} | select inputobject |  ft -hidetableheaders"
Run Code Online (Sandbox Code Playgroud)

请注意,我还删除了& { ... }您命令的周围,​​因为它不是必需的。


[1] eryksun将其描述如下:“这是 Windows 命令行不可避免的挫败感。每个程序都解析自己的命令行,使用它想要的任何规则。因此,命令行的语法不仅要与 shell 一起使用(CMD) 以及管道中调用的所有程序。在 Unix 世界中,shell 将命令行解析为argv数组,因此通常您只需要获得正确的语法即可使 shell 满意。”
PowerShell Core 的问题,即使在 Unix 上,也源于它在传递参数之前如何在幕后重新引用参数 - 请参阅此 GitHub 文档问题