2

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

有没有人可以想到优化此脚本以使其更快地工作?或者关于如何制作一个完全不同但运行速度更快的等效脚本的想法?

所有输入表示赞赏!

4

2 回答 2

2

假设 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"
}
于 2011-01-11T12:49:38.037 回答
2

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

$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 没有太多理由 - 纯文本文件每行一个路径就可以了。

于 2011-01-11T12:49:40.453 回答