Search 优化PowerShell中的简单搜索脚本

Search 优化PowerShell中的简单搜索脚本,search,powershell,optimizer-hints,Search,Powershell,Optimizer Hints,我需要创建一个脚本来搜索不到一百万个文本、代码等文件,以找到匹配项,然后将特定字符串模式的所有点击结果输出到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 $loca

我需要创建一个脚本来搜索不到一百万个文本、代码等文件,以找到匹配项,然后将特定字符串模式的所有点击结果输出到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”的所有文件列表

有没有任何人能想到的方法来优化这个脚本,使它工作得更快?或者是关于如何制作一个完全不同的、但效果相当的脚本,使其运行得更快的想法

感谢所有的意见

让我们假设1)文件不是太大,您可以将其加载到内存中;2)您只需要匹配的文件路径(而不是行等)

我尝试只读取一次文件,然后遍历正则表达式。有一些好处(比原始解决方案更快),但最终结果将取决于其他因素,如文件大小、文件数量等

另外,删除
'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"
}

如果您的文件不是很大,并且可以读入内存,那么这个版本应该运行得更快(我的快速脏本地测试似乎证明了这一点):


注:1)改变了示例中的路径和模式;2) 输出文件不是CSV,而是纯文本;如果您只对路径感兴趣,CSV中没有太多的理由——纯文本文件每行一条路径就可以了。

现在需要多少(只是出于好奇)?您是否只需要输出中包含匹配项的文件路径?现在阵列中的项目需要约2小时的pr。我刚刚学会了measure命令技巧,我将看看性能是否会随着进程的缓存而提高我只需要包含匹配项的文件路径,yesI还可以添加每个数组项(字符串)的长度似乎会显著影响处理时间。在第一次运行期间,CPU使用率约为15-20%。现在似乎在4-5%左右。有趣的东西。您的文件是否足够小,例如,可以将所有文本读入内存,或者这不是一个选项?文件总数可能太大,但这是一个有趣的想法。如果我能把它全部缓存在RAM中,我愿意在执行搜索之前拆分操作并一次缓存一个子目录。关于如何实现这一点,你有什么想法吗?太棒了,你比我快了2秒!:-)但我们的建议并不完全相同。因此,@cc0现在有了更多的选择,这是好事。这非常好:]希望其他人也能从中学习。谢谢你抽出时间!谢谢:)我也会试一试,看看哪一种更适合我的情况。应该很有趣!我会尽快完成:]可能需要几天时间,我会在这里对许多项目进行适当的测试。
$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"
        }
    }
}}}