如何在第一次匹配时停止管道过滤(Where-Object)

How to stop pipeline filtering (Where-Object) on first match

我搜索了,但还没有找到方法。
我正在从大文件 (~2GB) 中过滤数据。
我使用 Where-Object 并且当它找到匹配项时,它会继续搜索它有意义的其他匹配项。

是否可以在第一场比赛就停止?

例如(#1):

Get-Process | Where-Object {$_.ProcessName.StartsWith("svchost")}

输出将是:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    666      38    26928      18672    92             568 svchost
    596      28    11516      16560    92             792 svchost
    425      14     5364       7036    45             832 svchost
    406      17     7032       8416    39            1004 svchost

我要的是return第一次匹配后的输出:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    666      38    26928      18672    92             568 svchost

这是我尝试过的(也使用 Foreach-Object):

Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){return $_}}
Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){return $_;break;}}    
Get-Process | ForEach-Object {if($_.ProcessName.StartsWith("svchost")){return $_}}

但它仍然是 return 的完整输出。
参考:
How to break Foreach loop in Powershell?
Is it possible to terminate or stop a PowerShell pipeline from within a filter

编辑(大数据问题的解释):
示例 (#2):
我有两个 XML:
A.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Events>
  <Event>
    <EventData Name="Time">09/10/2017 12:54:16</EventData>
    <EventData Name="WorkstationName">USER2-PC</EventData>
    <EventData Name="UserName">user2</EventData>
  </Event>  
</Events>

B.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Events>
   <Event>
    <EventData Name="Time">09/10/2017 14:54:16</EventData>
    <EventData Name="WorkstationName">USER1-PC</EventData>
    <EventData Name="UserName">user1</EventData>
  </Event>
  <Event>
    <EventData Name="Time">09/10/2017 13:54:16</EventData>
    <EventData Name="WorkstationName">USER2-PC</EventData>
    <EventData Name="UserName">user2</EventData>
  </Event> 
 ... (more 100,000 events like the above two)
</Events>

这些 XML 正在作为对象加载:

$fileA = "C:\tmp\A.xml"
$a = New-Object Xml.XmlDocument
$a.Load($fileA)

$fileB = "C:\tmp\B.xml"
$b = New-Object Xml.XmlDocument
$b.Load($fileB)

然后我想搜索相同用户名的第一个匹配项:

$result = $b.Events.Event | Where-Object {
    (($_.EventData | where-object {$_.Name -eq "UserName"})."#text" -eq $username)
}

$result.EventData

在这种情况下,如果我在第一个事件中匹配,那么在其余 99,999 个事件中 运行 会浪费时间。

编辑(已解决):
看完尼克的回答后,没有什么新东西我没试过。
命令:

Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){ $_;break;}}  

确实停止了 Where-Object 但它没有 return 项目。
这个可以通过以下方式解决:

Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){ $someVar = $_;break;}}  

所以我标记了他的答案。

Where-ObjectForEach-Object 都是 Cmdlet。您不能破坏 Cmdlet(命令)。您可以做的是像这样使用关键字 foreach

$process = Get-Process

foreach ($item in $process) {
    if ($item.Name -eq 'svchost') {
        $item
        return
    }
}

要从大文件中过滤数据,请使用 StreamReader 而不是常规的 PowerShell cmdlet:

$filename = 'C:\path\to\your.txt'
$word     = 'something'

$rdr = [IO.File]::OpenText($filename)
while ($rdr.Peek() -ge 0) {
    $line = $rdr.ReadLine()
    if ($line -like "*${word}*") { break }
}
$rdr.Close()
$rdr.Dispose()

如果 efficiency 是您所需要的,您可以尝试将其分解为一个循环:

Get-Process | foreach {If ($_.ProcessName.StartsWith("svchost")){$_;break}}

您可以确认它适用于此检查:

$i=0; Get-Process | foreach {$i++;$i; If ($_.ProcessName.StartsWith("svchost")){$_;break}}

它会让循环在每次循环时打印出一个数字,在我的例子中它达到了 115,然后如果我这样做 (Get-Process).Count 我有 157 个进程,所以它循环了我的进程找到我们想要的然后停止循环。

如其他答案中所述,您可以使用 [0],在任何数组或列表上,您可以使用方括号内的索引 select 单独的行,但要小心,因为尝试这样做null 或空对象将引发异常:

(Get-Process | Where-Object {$_.ProcessName.StartsWith("svchost")})[0]

或者您可以 Select-Object,它以类似的方式工作,但除了 Index 之外还有更多选项,并且如果对象为 null 或空,则不会抛出任何错误。

Get-Process | Where-Object {$_.ProcessName.StartsWith("svchost")} | Select-Object -First 1

这两个选项如何仍然会在您 select 第一个结果之前评估整个列表。

超级有趣。不知道为什么,这篇文章与我们的发现相矛盾!

https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/save-time-with-select-object-first

我什至测试过它。由于 PS3,select-object -first 停止管道