【发布时间】:2017-09-20 16:44:15
【问题描述】:
我进行了搜索,但还没有找到方法。
我正在从大文件 (~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
我想要的是在第一次匹配后返回输出:
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 $_}}
但它仍然返回完整的输出。
参考:
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,但它不会返回该项目。
这个可以通过以下方式解决:
Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){ $someVar = $_;break;}}
因此我标记了他的答案。
【问题讨论】:
-
... | Where-Object { $_.ProcessName -like 'svchost*' } | Select-Object -First 1? -
如果您要过滤文件数据,为什么不使用带有 -List 选项的 Select-String 使其在第一次匹配时停止?
-
@AnsgarWiechers 它仍然会传递所有进程,在它使用 all 'svchost.exe' 进程获取对象后,它将选择第一个进程。您可以看到它通过:
Get-Process | Where-Object { $_.ProcessName -like 'svchost*'; Write-Host $_} | Select-Object -First 1传递所有对象
标签: powershell break pipeline