執行 PowerShell 模擬 *nix grep

執行 PowerShell 模擬 *nix grep

有沒有一種方法可以優化下面的 PowerShell 程式碼(它將一堆文字檔案中包含的字串按特定行 grep 到單一檔案中):

$ErrorActionPreference = "Continue"
Start-Transcript -path D:\0xAC1CC07A.log -append
$OutFile = "D:\0xAC1CC07A.txt"
echo "filtering 0xAC1CC07A"
ForEach ($filenm in ((get-childitem -Path D:\FILES\* -include ubuntlive1mb_?????_201509*.txt -recurse -force))) 
{
 $filenm.fullName;
 (Get-Content $filenm) | select-string "0xAC1CC07A" | Add-Content $OutFile
}
Stop-Transcript

它在小型工作負載上表現良好,但在處理 160K 文字檔案(總共超過 200GB)時,它在我的 Win2008R2 VM 上運行超過 4 天。令人驚訝的是,類似虛擬硬體上的 Ubuntu 14.04 在 4 小時內完成了這項工作:

grep --no-filename "0xac1cc07a" ./FILES/ubuntlive1mb_?????_201509*.txt >>./0xAC1CC07A.txt

或者更準確地說:

find ./FILES -name "ubuntlive1mb_?????_201509*.txt" -type f -print0 | xargs -0 grep --no-filename "0xac1cc07a" $1 >>./0xAC1CC07A.txt

我既不擅長 PowerShell 也不擅長 *nix,而以上所有腳本都是透過谷歌搜尋和複製貼上創建的。

Windows 盒子已透過停用 dos 檔案名稱和清單上的目錄更新來最佳化檔案系統。 Ubuntu 剛剛開箱即用安裝。

答案1

這個非常簡單的 Powershell 腳本應該可以滿足您的需求:

$OutFile = "D:\0xAC1CC07A.txt"
Get-ChildItem -Path D:\FILES\ubuntlive1mb_?????_201509*.txt -Recurse | Foreach-Object { Select-String -Path $_ -Pattern "0xAC1CC07A" } | Foreach-Object { Add-Content -Path $OutFile -Value $_.Line }

這只會將符合的行新增到 $OutFile 文字檔案中。您也可以使用 Filename、Path 和 LineNumber 屬性(而不僅僅是 Line 屬性)來取得檔案名稱或符合行的行號。

如果您想要測試將針對許多文件執行的腳本,但不想等待它完成檢查所有文件,那麼您可以使用 Select-Object cmdlet 來限制它將檢查的文件數量。

例子:

Get-ChildItem -Path D:\FILES\ubuntlive1mb_?????_201509*.txt | Select-Object -First 100 | Foreach-Object { Select-String -Path $_ -Pattern "0xAC1CC07A" } | Foreach-Object { Add-Content -Path $OutFile -Value $_.Line }

這將僅針對從 Get-ChildItem 傳回的前 100 個文字檔案執行上述腳本。

答案2

您的輸出會略有不同(但如果需要的話可以處理),但從我所見,直接在文件上選擇 Select-String 而不是獲取文件內容要快得多第一的。

Select-String "0xAC1CC07A" -Path $filenm.FullName | Add-Content $OutFile

只需記住在將輸出附加到文件之前先檢查輸出,以便以您想要的方式獲得它。

至於速度; Get-ChildItem 在 PowerShell 中是出了名的慢(因為 PowerShell 喜歡取得物件而不僅僅是物件的文字表示),並且有多種解決方法。

但是,程式碼中的 Get-ChildItem-line 可以進行最佳化。據我所知,在普通消費級 7.2k HDD 上使用過濾器比使用包含/排除快大約 3.5 倍。

Get-ChildItem -Path "D:\FILES" -Filter "ubuntlive1mb_?????_2015090101*.txt" -Recurse -Force

如果我沒記錯的話,早期版本的 PowerShell 在過濾方面存在一些問題,例如,如果您想要所有擴展名為 .htm 的文件,它也會選取擴展名為 .html 的文件(就好像您已過濾*.htm*但未過濾一樣*.htm),所以你可能要留意這一點。

相關內容