在PowerShell中优化简单的搜索脚本
-
09-10-2019 - |
题
我需要创建一个脚本来搜索仅在一百万个文本,代码等的文件以下,以查找匹配项,然后输出特定字符串模式上的所有命中,向CSV文件输出。
到目前为止,我做了这个;
$location = 'C:\Work*'
$arr = "foo", "bar" #Where "foo" and "bar" are string patterns I want to search for (separately)
for($i=0;$i -lt $arr.length; $i++) {
Get-ChildItem $location -recurse | select-string -pattern $($arr[$i]) | select-object Path | Export-Csv "C:\Work\Results\$($arr[$i]).txt"
}
这将返回给我一个名为“ foo.txt”的CSV文件,其中包含所有文件的列表,其中包含“ foo”一词,还有一个名为“ bar.txt”的文件,其中包含包含单词“ bar”的所有文件列表。
是否有人想到任何方法来优化此脚本以使其更快地工作?还是关于如何制作完全不同但等效脚本的想法?
所有输入都赞赏!
解决方案
如果您的文件不大并且可以读取为内存,那么此版本的工作速度应该更快(我的快速而肮脏的本地测试似乎证明了这一点):
$location = 'C:\ROM'
$arr = "Roman", "Kuzmin"
# remove output files
foreach($test in $arr) {
Remove-Item ".\$test.txt" -ErrorAction 0 -Confirm
}
Get-ChildItem $location -Recurse | .{process{ if (!$_.PSIsContainer) {
# read all text once
$content = [System.IO.File]::ReadAllText($_.FullName)
# test patterns and output paths once
foreach($test in $arr) {
if ($content -match $test) {
$_.FullName >> ".\$test.txt"
}
}
}}}
注意:1)思维改变了示例中的路径和模式; 2)输出文件不是CSV,而是纯文本; CSV中没有太多原因,如果您仅对路径感兴趣 - 纯文本文件每行只能做一条路径。
其他提示
让我们假设1)文件不太大,您可以将其加载到内存中,2)您真的只需要文件的路径,与之匹配(不是行等)。
我尝试只读一次文件,然后通过Regexes迭代。有一些增益(比原始解决方案更快),但最终结果将取决于其他因素,例如文件大小,文件计数等。
也删除 'ignorecase'
使其更快一点。
$res = @{}
$arr | % { $res[$_] = @() }
Get-ChildItem $location -recurse |
? { !$_.PsIsContainer } |
% { $file = $_
$text = [Io.File]::ReadAllText($file.FullName)
$arr |
% { $regex = $_
if ([Regex]::IsMatch($text, $regex, 'ignorecase')) {
$res[$regex] = $file.FullName
}
}
}
$res.GetEnumerator() | % {
$_.Value | Export-Csv "d:\temp\so-res$($_.Key).txt"
}
不隶属于 StackOverflow