Powershell:将外部命令输出通过管道传输到另一个外部命令
Posted
技术标签:
【中文标题】Powershell:将外部命令输出通过管道传输到另一个外部命令【英文标题】:Powershell: Pipe external command output to another external command 【发布时间】:2013-10-13 19:06:06 【问题描述】:我怎样才能让 PowerShell 理解这种类型的东西:
Robocopy.exe | Find.exe "Started"
旧的命令处理器给出了结果,但我对如何在 PowerShell 中执行此操作感到困惑:
&robocopy | find.exe "Started" #error
&robocopy | find.exe @("Started") #error
&robocopy @("|", "find.exe","Started") #error
&robocopy | &find @("Started") #error
&(robocopy | find "Started") #error
本质上,我想将一个外部命令的输出通过管道传输到另一个外部命令。实际上,我将调用 flac.exe 并将其导入 lame.exe 以将 FLAC 转换为 MP3。
干杯
【问题讨论】:
如果 .exe 不是为接受管道而设计的,你就不能.. Find.exe 被设计为接受管道,就像 lame.exe 一样。我得到的任何错误都是来自 Powershell 不理解我的意思。您可以尝试在 cmd.exe 中查找示例 【参考方案1】:tl;dr
# Note the nested quoting. CAVEAT: May break in the future.
robocopy.exe | find.exe '"Started"'
# Alternative. CAVEAT: doesn't support *variable references* after --%
robocopy.exe | find.exe --% "Started"
# *If available*, use PowerShell's equivalent of an external program.
# In lieu of `findstr.exe`, you can use Select-String (whose built-in alias is scs):
# Note: Outputs are *objects* describing the matching lines.
# To get just the lines, pipe to | % ToString
# or - in PowerShell 7+ _ use -Raw
robocopy.exe | sls Started
有关解释,请继续阅读。
PowerShell 确实支持与外部程序之间的管道。
这里的问题是参数解析和传递之一:find.exe
有一个奇怪的要求,即它的 搜索词必须用 literal 双引号括起来。
在cmd.exe
中,简单的双引号就足够了:find.exe "Started"
相比之下,默认情况下,PowerShell 在传递参数之前预先解析参数,如果逐字参数值不包含空格,则 去除 括起来的引号 em>,这样find.exe
只能看到Started
,没有双引号,导致错误。
有三种方法可以解决这个问题:
PS v3+(仅当您的参数只有文字和/或环境变量时才可以选择):--%
,@987654321 @,告诉 PowerShell 将命令行的 rest按原样传递给目标程序(引用环境变量,如果有的话,cmd-风格 (%<var>%
)):robocopy.exe | find.exe --% "Started"
--%
的限制。
PS v2 也可以,或者如果您需要在参数中使用 PowerShell 变量:应用 PowerShell 引用的外层(PowerShell 将去掉单引号并将字符串的内容按原样传递给find.exe
,并保持双引号不变):robocopy.exe | find.exe '"Started"'
""Started""
,这会中断调用 - 请参阅 this answer 了解更多信息。李>
如果有类似的 PowerShell 命令可用,请使用它,这样可以避免所有引用问题。在这种情况下,Select-String
cmdlet ,可以使用PowerShell对findstr.exe
的更多powershell模拟,如上图。
【讨论】:
【参考方案2】:@Jobbo:cmd 和 PowerShell 是两个不同的 shell。有时可以混合它们,但正如您从 Shay 的回答中意识到的那样,它不会让您走得太远。但是,您可能在这里问错了问题。
大多数时候,您尝试解决的问题(例如通过管道连接到 find.exe)甚至都不是必需的。 你在 Powershell 中确实有 find.exe 的等价物,实际上是更强大的版本:select-string
您始终可以运行命令并将结果分配给变量。
$results = Robocopy c:\temp\a1 c:\temp\a2 /MIR
结果将是 STRING 类型,您可以使用许多工具对其进行切片和切块。
PS > $results |select-string "started"
Started : Monday, October 07, 2013 8:15:50 PM
【讨论】:
【参考方案3】:通过 cmd 调用它:
PS> cmd /c 'Robocopy.exe | Find.exe "Started"'
【讨论】:
这行得通,但是如果我的命令有很多参数传递给它们(它们确实如此),那么我会失去在数组中传递参数的好处,比如@(,,,)?有什么方法可以在不涉及 cmd.exe 的情况下做到这一点? 这行得通,但读起来却是一场噩梦:&cmd @("/c",@('robocopy','|','find "Started"'))在将其全部构建为一个字符串和嵌套数组之间? 我知道这种感觉...我会在 cmd 文件中编写超过一行的命令并执行它。 哇,这真是衣衫褴褛。我想知道我是否可以使用管道连接到 Out-Host 或其他东西?我发现我可以使用 Tee-Object 将 Robocopy 的输出转换为变量,但随后只需将变量通过管道传输到外部命令中,例如:$out | &find.exe 这似乎是不可能的以上是关于Powershell:将外部命令输出通过管道传输到另一个外部命令的主要内容,如果未能解决你的问题,请参考以下文章
Windows CLI:将列表通过管道传输到 awk 并用外部文件中的文本替换文本并写入 output.txt