【问题标题】:problem with powershell and cmd with pipespowershell 和 cmd 的问题与管道
【发布时间】:2021-06-29 05:08:16
【问题描述】:

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

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

我正在尝试通过这样做在 cmd 中运行:

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

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

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

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

【问题讨论】:

  • 不,不是管道。对于 CMD,此命令类似于以下元素:" &amp; {Compare-Object (Get-Content "、tex1.txt、") (Get-Content "、tex2.txt、") | Where-Object{$_.SideIndicator -eq "、&lt;=、"} | select inputobject | ft -hidetableheaders}"。对于“< 标准输入重定向。为此,它尝试打开“} | select inputobject | ft -hidetableheaders}”进行读取,但由于“|”而失败,ERROR_INVALID_NAME是文件系统中的保留字符(例如 NTFS 或 FAT)。
  • 在命令中,尝试用 APOSTROPHE 字符替换 QUOTE 字符。

标签: powershell cmd


【解决方案1】:

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 的部分,这会导致 | 和 &lt; 等特殊字符出现问题 - 它们永远不会到达 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 &amp; b"^"" " 产生 a &amp; b,正如预期的那样,&amp; 不需要转义。
  • 如果您使用更简单的 - 和惯用的 - \",您可能需要执行额外的转义:具体来说,您 必须单独^-escape以下cmd.exe元字符在^内\"...\"运行:&amp; | &lt; &gt; ^谢谢LotPings。

    • 示例:powershell -command " Write-Output \"a ^&amp; b\" " 产生a &amp; b;也就是说,&amp; 需要用 ^ 转义。
  • 此外,要处理%(以及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 时,您通常可以摆脱 不需要嵌入 双 引号:

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

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

把它们放在一起:

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

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


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

【讨论】:

    猜你喜欢
    • 2021-06-28
    • 1970-01-01
    • 1970-01-01
    • 2012-10-22
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 2021-06-06
    相关资源
    最近更新 更多