我撰寫了這個腳本來搜索大量文本檔案 (~100,000) 以獲取 4 個不同的搜索條件并匯出到 4 個單獨的檔案,我認為在加載每個檔案時對每個檔案執行所有 4 次搜索比執行 4 次完整搜索更有效像下面的第一次迭代一樣搜索。我可能會遺漏其他一些主要的低效問題,因為我對 powershell 還很陌生。
我將此腳本從第一個版本重新撰寫到第二個版本,但無法弄清楚如何像第一個版本一樣將路徑和資料一起顯示。我正在努力參考回圈中的物件,并將第二個版本拼湊在一起,這是有效的,但沒有給我必要的檔案路徑。
似乎我只是缺少一兩件小事來讓我朝著正確的方向前進。在此先感謝您的幫助
第一個版本:
Get-ChildItem -Filter *.txt -Path "\\file\to\search" -Recurse | Select-String -Pattern "abc123" -Context 0,3 | Out-File -FilePath "\\c:\out.txt"
Get-ChildItem -Filter *.txt -Path "\\file\to\search2" -Recurse | Select-String -Pattern "abc124" -Context 0,3 | Out-File -FilePath "\\c:\out2.txt"
Get-ChildItem -Filter *.txt -Path "\\file\to\search3" -Recurse | Select-String -Pattern "abc125" -Context 0,3 | Out-File -FilePath "\\c:\out3.txt"
Get-ChildItem -Filter *.txt -Path "\\file\to\search4" -Recurse | Select-String -Pattern "abc126" -Context 0,3 | Out-File -FilePath "\\c:\out4.txt"
輸出:
\\file\that\was\found\example.txt:84: abc123
\\file\that\was\found\example.txt:90: abc123
\\file\that\was\found\example.txt:91: abc123
第二個版本:
##$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Configuration $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
############################################ Global Parameters #############################################
$SearchPath="\\file\to\search"
$ProgressFile=""\\progress\file\ResultsCount.txt"
$records = 105325
##----------------------------------------- End Global Parameters -----------------------------------------
########################################### Search Parameters ##############################################
##Search Pattern 1
$Pattern1="abc123"
$SaveFile1="\\c:\out.txt"
##Search Pattern 2
$Pattern2="abc124"
$SaveFile2="\\c:\out2.txt"
##Search Pattern 3
$Pattern3= "abc125"
$SaveFile3= "\\c:\out3.txt"
##Search Pattern 4
$Pattern4= "abc126"
$SaveFile4="\\c:\out4.txt"
##Search Pattern 5
$Pattern5= ""
$SaveFile5=""
##----------------------------------------- End Search Parameters ------------------------------------------
##$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ End of Config $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
############################### SCRIPT #####################################################################
## NOTES
## ------
##$files=Get-ChildItem -Filter *.txt -Path $SearchPath -Recurse ## Set all files to variable #### Long running, needs to be a better way #######
##$records=$files.count ## Set record #
Get-ChildItem -Filter *.txt -Path $SearchPath -Recurse | Foreach-Object { ## loop through search folder
$i=$i 1 ## increment record
##
Get-Content $_.FullName | Select-String -Pattern $Pattern1 -Context 0,3 | Out-File -FilePath $SaveFile1 ## pattern1 search
Get-Content $_.FullName | Select-String -Pattern $Pattern2 | Out-File -FilePath $SaveFile2 ## pattern2 search
Get-Content $_.FullName | Select-String -Pattern $Pattern3 -Context 0,1 | Out-File -FilePath $SaveFile3 ## pattern3 search
Get-Content $_.FullName | Select-String -Pattern $Pattern4 -Context 0,1 | Out-File -FilePath $SaveFile4 ## pattern4 search
##Get-Content $_.FullName | Select-String -Pattern $Pattern5 -Context 0,1 | Out-File -FilePath $SaveFile5 ## pattern5 search (Comment out unneeded search lines like this one)
$progress ="Record $($i) of $($records)" ## set progress
Write-Host "Record $($i) of $($records)" ## Writes progress to window
$progress | Out-File -FilePath $ProgressFile ## progress file
} ##
############################################################################################################
輸出:
abc123
abc123
abc123
編輯:此外,我試圖找出一種不必對記錄數量進行硬編碼以獲得不錯的進度讀數的好方法,我注釋掉了我認為可以作業的方式(腳本的第一行和第二行),但是有需要比重新運行相同的搜索兩次更有效,一次用于計數,一次用于 for 回圈。
我對您可以提供的任何運行時效率資訊都非常感興趣。
uj5u.com熱心網友回復:
[編輯 - 感謝 mklement0 指出有關速度和-SimpleMatch開關的錯誤。[咧嘴笑]]
該Select-Stringcmdlet將接受一個-Path引數...它是FAR [我在想Get-Content,不Get-ChidItem]比使用更快Get-ChildItem的檔案喂S-S。[咧嘴笑]
此外,該-Pattern引數接受OR像Thing|OtherThing|YetAnotherThing- 這樣的正則運算式模式,如果您使用-SimpleMatchswitch 引數,它接受簡單的字串模式。
代碼做什么...
- 定義源目錄
- 定義檔案規范
- 將這兩個加入通配符檔案路徑
- 構建要使用的字串模式陣列
Select-String帶有路徑和要搜索的字串陣列的呼叫- 使用
Group-Object和計算的屬性按.Line來自S-S呼叫的屬性的最后部分對匹配項進行分組 - 將其保存到 $Var
- 在螢屏上顯示
此時,您可以使用.Nameeach的屬性GroupInfo來選擇要發送到每個檔案的專案并構建您的檔案名。
代碼 ...
$SourceDir = 'D:\Temp\zzz - Copy'
$FileSpec = '*.log'
$SD_FileSpec = Join-Path -Path $SourceDir -ChildPath $FileSpec
$TargetPatternList = @(
'Accordion Cajun Zydeco'
'better-not-be-there'
'Piano Rockabilly Rowdy'
)
$GO_Results = Select-String -Path $SD_FileSpec -SimpleMatch $TargetPatternList |
Group-Object -Property {$_.Line.Split(':')[-1]}
$GO_Results
輸出 ...
Count Name Group
----- ---- -----
6 Accordion Cajun Zydeco {D:\Temp\zzz - Copy\Grouping-List_08-02.log:11:Accordion Cajun Zydeco, D:\Temp\zzz - Copy\Grouping-List_08-09.log:11:Accordion Cajun Zy...
6 Bawdy Dupe Piano Rocka... {D:\Temp\zzz - Copy\Grouping-List_08-02.log:108:Bawdy Dupe Piano Rockabilly Rowdy, D:\Temp\zzz - Copy\Grouping-List_08-09.log:108:Bawdy...
6 Bawdy Piano Rockabilly... {D:\Temp\zzz - Copy\Grouping-List_08-02.log:138:Bawdy Piano Rockabilly Rowdy, D:\Temp\zzz - Copy\Grouping-List_08-09.log:138:Bawdy Pian...
6 Dupe Piano Rockabilly ... {D:\Temp\zzz - Copy\Grouping-List_08-02.log:948:Dupe Piano Rockabilly Rowdy, D:\Temp\zzz - Copy\Grouping-List_08-09.log:948:Dupe Piano ...
6 Instrumental Piano Roc... {D:\Temp\zzz - Copy\Grouping-List_08-02.log:1563:Instrumental Piano Rockabilly Rowdy, D:\Temp\zzz - Copy\Grouping-List_08-09.log:1563:I...
6 Piano Rockabilly Rowdy {D:\Temp\zzz - Copy\Grouping-List_08-02.log:1781:Piano Rockabilly Rowdy, D:\Temp\zzz - Copy\Grouping-List_08-09.log:1781:Piano Rockabil...
請注意,.Group包含來自S-S呼叫發出的匹配項的行陣列。您可以將其發送到您的輸出檔案。
uj5u.com熱心網友回復:
這是我解決這個問題的看法,與Lee_Dailey 的好答案非常相似,但有一個foreach回圈。我建議花一些時間研究 PowerShell 上可用的多執行緒選項,以防您需要提高腳本的性能,您可以專門查看Microsoft的ThreadJob模塊,它非常易于使用,或者如果您不能由于某些作業策略安裝模塊,您可以使用Runspace。
值得補充的是,您可以使用-Listswitch on Select-String,這樣腳本的性能會得到更多的提高:
-List
每個輸入檔案只回傳匹配文本的第一個實體。這是檢索內容與正則運算式匹配的檔案串列的最有效方法。
$map = @{
abc123 = 'C:\out_abc123.txt'
abc124 = 'C:\out_abc124.txt'
abc125 = 'C:\out_abc125.txt'
}
$pattern = $map.Keys -join '|'
$match = foreach($file in Get-ChildItem *.txt)
{
Select-String -LiteralPath $file.FullName -Pattern $pattern
}
$match | Group-Object { $_.Matches.Value } | ForEach-Object {
$_.Group | Select-Object Path, LineNumber, Line | Out-File $map[$_.Name]
}
uj5u.com熱心網友回復:
為了贊美@Santiago Squarzon和Lee_Dailey的答案,我認為您實際上是在了解Group-Objectcmdlet 非常昂貴,尤其是在記憶體使用方面,因為它阻塞了 PowerShell管道,導致所有搜索結果都堆積在記憶體中。
此外,您的文字搜索字串表明您可能想要做一個Select-String -SimpleMatch ...而不是-Pattern匹配。
繼續您的方法:(
請注意,在示例中,我使用自己的設定來搜索我的腳本檔案)
$ProgressFile = '.\ResultsCount.txt'
$SearchRoot = 'C:\Users\Gebruiker\Scripts'
$Filter = '*.ps1'
$Searches = ConvertFrom-Csv @'
Pattern, File
Null, .\Null.txt
Test, .\Test.txt
Object, .\Object.txt
'@
$Files = Get-ChildItem -Filter $Filter -Path $SearchRoot -Recurse
$Total = $Files.count
$Searches |ForEach-Object { Set-Content -LiteralPath $_.File -Value '' }
$i = 0
$Files |ForEach-Object {
$Path = $_.FullName
$Content = Get-Content -LiteralPath $Path
ForEach ($Search in $Searches) {
$Content |Select-String $Search.Pattern |
ForEach-Object { '{0}:{1}:{2}' -f $Path, $_.LineNumber, $_ } |
Add-Content -LiteralPath $Search.File
}
'Record {0} of {1}' -f $i , $Total |Tee-Object -Append .\ProgressFile.txt
}
說明
$Searches = ConvertFrom-Csv @'...
我建議使用PSObject串列來指定每個搜索(您可以添加列背景關系開始/結束值等)$Searches |ForEach-Object { Set-Content -LiteralPath $_.File -Value '' }
清空結果檔案(知道它們不是您不能使用的主流的一部分Add-Content)$i = 0
不幸的是,沒有用foreach回圈初始化的自動索引(但是,請參閱:#13772管道索引的自動變數)$Content = Get-Content -LiteralPath $Path
將內容一次加載到記憶體中
注意1:這是一個字串陣列。
注2:當前項$_和$Content每次迭代都會被重用,因此會覆寫前一項并將其從記憶體中卸載$Content |Select-String $Search.Pattern
使用您定義的模式搜索字串陣列。(-SimpleMatch如果您的搜索字串包含特殊字符,您可能會考慮使用該引數。)ForEach-Object { '{0}:{1}:{2}' -f $Path, $_.LineNumber, $_ }
構建結果輸出字串。
注意:結果Selext-String確實有一個(隱藏的)LineNumber屬性。Add-Content -LiteralPath $Search.File
將結果字串添加到特定的輸出檔案。'Record {0} of {1}' -f $i , $Total |Tee-Object -Append .\ProgressFile.txt
Tee-Object將進度寫入標準輸出(顯示)和特定檔案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/392525.html
標籤:电源外壳 powershell-2.0 powershell-3.0 powershell-4.0
