2017-09-20 46 views
0

我搜索了,但沒有找到如何去做。
我正在從大文件(〜2GB)過濾數據。
我使用Where-Object,當它找到匹配時,它繼續搜索它有意義的其他匹配。如何在第一次匹配時停止管道過濾(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 

這就是我三ed(也用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

EDIT(約大數據的問題的解釋):
實施例(#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個事件。

EDIT(解決):
閱讀尼克的答案後,有沒有什麼新的東西我沒有嘗試。
命令:

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

事實上停止Where-Object,但它不返回該項目。
這可以通過解決:

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

所以我標誌着他的答案。

+2

'... | Where-Object {$ _。ProcessName-like'svchost *'} | Select-Object -First 1'? –

+1

如果您正在過濾文件數據,爲什麼不使用帶有-List選項的Select-String使它在第一次匹配時停止? – mjolinor

+0

@AnsgarWiechers它仍然會傳遞所有進程,並且在它將獲得** all **'svchost.exe'進程的對象後,它將選擇第一個進程。你可以看到它傳遞了所有的對象:'Get-Process | Where-Object {$ _。ProcessName-like'svchost *';寫主機$ _} | Select-Object-First 1' – E235

回答

0

如果效率是你所需要的你可以嘗試把它分解成一個循環:

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

你可以確認它可以用這個chec K:

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

它會在每次循環時間使循環打印出一個數字,在我的情況下,它得到了115,然後,如果我這樣做(Get-Process).Count我有157過程,因此,它環繞在我的過程中發現的一個我們想要,然後停止循環。

正如在其他答案中所述,您可以使用[0],在任何數組或列表中,您可以使用方括號內的索引選擇單個行,但要小心,因爲在null或空對象上嘗試這樣會引發異常:

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

或者你可以在你Select-Object,其以相似的方式工作,但有更多的選擇不僅僅是指數,如果對象爲空或空不會引發任何錯誤。

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

在選擇第一個結果之前,這兩個選項仍然會評估整個列表。

+0

效率是我所需要的,這很重要。關於你提到的最後兩個答案,就像你寫的那樣,他們仍然評估整個列表,因此我對他們並不感興趣。關於你的第一個建議,它是好的,我也嘗試過,但它不返回請求項目。但是我可以通過保存請求的變量'{$ someVar = $ _; break}'來解決這個問題。 – E235

1

Both,Where-ObjectForEach-Object是Cmdlet。您不能打破Cmdlet(命令)。你可以做的反而是使用關鍵字foreach這樣

$process = Get-Process 

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

我想你打算在這裏使用'break'而不是'return'。 –

+0

@vrdse此解決方法的問題仍然是傳遞所有對象。更重要的是,你做了兩次。第一次使用:'$ process = Get-Process',第二次使用循環:'foreach($ process in $ process)'。在這種情況下,使用Where-Object更快。 – E235

+0

我認爲這很大程度上取決於在循環中找到第一個項目,不是嗎? – vrdse

0

對於過濾數據,從大文件中使用StreamReader,而不是常規的PowerShell命令的:

$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() 
+0

我編輯了我的問題,我爲我正在處理的大數據添加了示例。在這種數據中,我將數據加載爲XML對象,所以在這種情況下,我看不到如何使用StreamReader。我最好的事情是使用管道「Where-Object」,但我無法阻止它在第一場比賽 – E235

+0

我可以使用'foreach($ event.Event.Event中的$ event){...}'但我認爲在管道中使用「Foreach-Object」會更快。 – E235

+0

[也許有關](https://stackoverflow.com/q/26820590/1630171)。 –

相關問題