Powershell和管道的cmd问题 [英] problem with powershell and cmd with pipes

查看:70
本文介绍了Powershell和管道的cmd问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有此命令可以在Powershell上正常工作

 比较对象(获取内容 tex1.txt)(获取内容 tex2.txt)| Where-Object {$ _。SideIndicator -eq< =} |选择输入对象| ft -hidetableheaders 

我正在尝试通过以下方式在cmd中运行:

  powershell-命令& {比较对象(Get-Content tex1.txt)(Get-Content tex2.txt)|其中-Object {$ _。SideIndicator -eq< =} |选择输入对象| ft -hidetableheaders} 

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



我认为问题是管道,因为在管道之前运行所有内容:比较对象(Get-Content tex1.txt)(Get-Content tex2.txt)有效



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

解决方案

tl; dr



调用PowerShell CLI powershell.exe for Windows PowerShell pwsh 跨平台 PowerShell [Core] 6 + 版):




  • 使用嵌入式<$ c $在整个 ... 字符串中的c> 都带有逃避挑战。


  • 如果对给定命令可行,则将其表示为嵌入 是最简单的解决方案:




  powershell-命令比较对象(获取-Content tex1.txt)(获取内容tex2.txt)| Where-Object {$ _。SideIndicator -eq’< =’} |选择输入对象| ft -hidetableheaders 

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






eryksun 指出,您的问题是您缺少转义的 字符。 $ c> ... 字符串,这会导致 cmd.exe 查看多个字符串,包括其组成部分考虑不带引号的,这会导致特殊字符(例如 | < )出现问题-永远不会到达 PowerShell



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




  • 使 cmd.exe 开心,则需要 double 嵌入的 字符。 (

  • 分别使 powershell.exe 高兴,您需要 \ -转义 字符。


    • 注意:Windows上的PowerShell [Core] 6+(跨平台版本)现在也接受 本身,这是最可靠的选择。 / li>



通常,从 cmd.exe 是令人沮丧的体验,没有通用解决方案,这与Unix世界不同,可悲的是, PowerShell 甚至在Unix世界中也面临着自己的挑战。 [1]



简而言之:转义嵌入的 字符。从 cmd.exe 调用 Windows PowerShell 时,如下所示:




  • 在使用 powershell.exe时使用 \ (原文如此)-命令 如果保持空白不变是必需的

    使您免于额外的转义,但是不会保留 \ ... \ 运行之间的空格,因此此方法不适合例如,用于传递JSON字符串。




    • 注意事项 \ 不能用于调用其他程序

    • 示例 powershell-命令 Write-Output \ a& b\ 产生 a& b ;也就是说,虽然& 不需要转义,但其周围的双空格每个都折叠成一个空格。


  • 在所有其他情况下都使用 \ ,但随后您需要分别 ^ -escape 以下 cmd.exe 元字符,其中<$ c $ $ ... inside 内的c> ^ 运行:& |<> ^ 谢谢, LotPings




    • 示例 powershell-命令 Write-Output \ a ^& b \ 产生 a& b ;即需要的& ^ 转义,但是正确保留了周围的双精度空格。


    • 另外,用于处理<从字面上code>%(以及 enabledelayedexpansion ),从字面上看,不幸的是,转义语法取决于她是从命令行批处理文件调用的:使用%^ USERNAME%!^ USERNAME )和 %% USERNAME %% ^!USERNAME ^! / ^^!USERNAME ^^! \ ... \ 运行),请参见此答案以了解详细信息。


    • 毋庸置疑,实现上述操作是一项繁琐且容易出错的任务,并非易事。

    • \ virtually 实际上受所有程序(批处理文件除外)的支持,如果不是为了满足这些额外的转义要求,则使用它的命令行有可能跨不同的平台和Shell运行-从PowerShell调用的明显例外,不幸的是,其中需要附加转义层,并且在内包含 。 .. 必须被转义为 \` cc(原文如此)。




有关避免避免使用 来缓解逃避痛苦的方法,请参见底部。 / p>




其他程序,包括PowerShell Core




  • 使用 just 用于使用 Microsoft 编译器编译的程序,在Windows上还用于 Python Node.js 以及PowerShell 核心 pwsh.exe

    遗憾的是,此功能强大的选项起作用使用 powershell.exe ,即 Windows PowerShell


  • \ 用于具有Unix遗产的程序,例如Perl和Ruby -上面讨论了不可避免的麻烦。 / p>







避免嵌入



调用PowerShell的CLI时,您常常可以不使用需要嵌入引号




  • 您的文件中可能有参数完全不需要引用的字符串,例如 text1.txt text2.txt


  • 您也可以在整体内部使用引号('...')命令字符串,不需要转义;请注意,从PowerShell的角度来看,这样的字符串是字符串 literals




全部在一起:

  powershell-命令比较对象(Get-Content tex1.txt)(Get-Content tex2.txt) | where对象{$ _。SideIndicator -eq'< ='} |选择inputobject | ft -hidetableheaders 

请注意,我还删除了& {...} ,因为它不是必需的。






[1] eryksun 表示如下:这是Windows命令行不可避免的挫败感每个程序都会使用所需的规则来解析自己的命令行,因此命令行的语法不仅必须与外壳程序(CMD)一起使用,而且还必须与管道中调用的所有程序一起使用。命令行放入 argv 数组中,因此通常您只需要正确使用语法即可使shell满意。

PowerShell Core的问题,甚至在Unix上,源于在传递参数之前如何在后台重新引用参数-请参见此GitHub文档问题


I have this command that works ok on powershell

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

I'm trying to running in cmd by doing this:

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

but it says something like: the name, the directory or the volume syntax is incorrect (is in spanish so i dont know the exact translation)

I think the problem is the pipes, since running everything before the pipe: Compare-Object (Get-Content "tex1.txt") (Get-Content "tex2.txt") works

PD: I also tried to write ^ before the pipes but I haven't succeeded.

解决方案

tl;dr

When calling the PowerShell CLI (powershell.exe for Windows PowerShell, pwsh for the cross-platform PowerShell [Core] 6+ edition):

  • Using embedded " in an overall "..." string comes with escaping challenges.

  • If feasible for a given command, formulating it without embedded " is the easiest solution:

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

Read on, if you do need to use embedded ".


eryksun points out that your problem is your lack of escaping of embedded " chars. inside the overall "..." string, which causes cmd.exe to see multiple strings, including parts it considers unquoted, which causes problems with special characters such as | and < - they never reach PowerShell.

Nesting double-quote strings from cmd.exe is tricky business:

  • To make cmd.exe happy, you need to double the embedded " chars. ("")
  • Separately, to make powershell.exe happy, you need to \-escape " chars.
    • Note: PowerShell [Core] 6+, the cross-platform edition, on Windows now also accepts "" by itself, which is the most robust choice.

Generally, dealing with quoting and escaping arguments when calling from cmd.exe is a frustrating experience with no universal solutions, unlike in the Unix world. Sadly, PowerShell has its own challenges, even in the Unix world.[1]

In short: Escape embedded " chars. when calling Windows PowerShell from cmd.exe as follows:

  • Use \"" (sic) when using powershell.exe -Command if preserving whitespace as-is is not required.
    This saves you from additional escaping, but the whitespace between \""...\"" runs isn't preserved, so this method is not suitable for passing a JSON string, for instance.

    • Caveat: \"" will not work for calling other programs.
    • Example: powershell -command " Write-Output \""a & b\"" " yields a & b; that is, while the & didn't need escaping, the double spaces around it were folded into a single space each.
  • Use \" in all other cases, but you then need to individually ^-escape the following cmd.exe metacharacters with ^ inside \"...\" runs: & | < > ^Thanks, LotPings.

    • Example: powershell -command " Write-Output \"a ^& b\" " yields a & b; that is, the & needed escaping with ^, but the double spaces around it were correctly preserved.

    • Additionally, to treat % (and, with enabledelayedexpansion , !) literally, the escaping syntax unfortunately depends on whether you're calling from the command line or a batch file: use %^USERNAME% (!^USERNAME) from the former, and %%USERNAME%% (^!USERNAME^! / ^^!USERNAME^^! inside \"...\" runs) from the latter - see this answer for the gory details.

    • Needless to say, implementing the above is a cumbersome and error-prone task that is not trivial to automate.
    • \" is supported by virtually all programs (except batch files), and if it weren't for these extra escaping requirements, command lines that use it have the potential to work across different platforms and shells - with the notable exception of calling from PowerShell, where, sadly, an additional layer of escaping is needed and " inside "..." must be escaped as \`" (sic).

See the bottom section for ways to ease the escaping pain by avoiding use of ".


Other programs, including PowerShell Core:

  • Use just "" for programs compiled with Microsoft compilers and, on Windows, also Python and Node.js as well as PowerShell Core (pwsh.exe).
    Regrettably, this robust option does not work with powershell.exe, i.e. Windows PowerShell.

  • Use \" for programs with Unix heritage, such as Perl and Ruby - which comes with the escaping headaches discussed above.


Avoiding embedded ":

When you call PowerShell's CLI, you can often get away without needing to embed double quotes:

  • There may be arguments in your string that don't require quoting at all, such as text1.txt and text2.txt

  • You can alternatively use single-quoting ('...') inside the overall command string, which require no escaping; note that such strings, from PowerShell's perspective, are string literals.

To put it all together:

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

Note that I've also removed the & { ... } around your command, as it isn't necessary.


[1] eryksun puts it as follows: "This is the inescapable frustration of the Windows command line. Every program parses its own command line, using whatever rules it wants. So the syntax of a command line has to work with not only the shell (CMD) but also all programs invoked in the pipeline. In the Unix world the shell parses the command line into argv arrays, so typically you only have to get the syntax right to make the shell happy."
The problems with PowerShell Core, even on Unix, stem from how it re-quotes arguments behind the scenes before passing them on - see this GitHub docs issue.

这篇关于Powershell和管道的cmd问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆