Performance 提高我的PowerShell脚本的效率
下面的代码从list.txt文件中搜索400多个数字,以查看它是否存在于指定文件夹路径内的任何文件中 脚本速度非常慢,尚未完成,因为它在运行25分钟后未完成。我们正在搜索的文件夹为507MB(532369408字节),其中包含1119个文件,480个文件夹。我们非常感谢任何有助于提高搜索速度和效率的帮助Performance 提高我的PowerShell脚本的效率,performance,powershell,coding-efficiency,Performance,Powershell,Coding Efficiency,下面的代码从list.txt文件中搜索400多个数字,以查看它是否存在于指定文件夹路径内的任何文件中 脚本速度非常慢,尚未完成,因为它在运行25分钟后未完成。我们正在搜索的文件夹为507MB(532369408字节),其中包含1119个文件,480个文件夹。我们非常感谢任何有助于提高搜索速度和效率的帮助 $searchWords = (gc 'C:\temp\list.txt') -split ',' $results = @() Foreach ($sw in $searchWords) {
$searchWords = (gc 'C:\temp\list.txt') -split ','
$results = @()
Foreach ($sw in $searchWords)
{
$files = gci -path 'C:\Users\david.craven\Dropbox\Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*' -filter "*$sw*" -recurse
foreach ($file in $files)
{
$object = New-Object System.Object
$object | Add-Member -Type NoteProperty –Name SearchWord –Value $sw
$object | Add-Member -Type NoteProperty –Name FoundFile –Value $file.FullName
$results += $object
}
}
$results | Export-Csv C:\temp\output.csv -NoTypeInformation
以下几点可以大大加快您的任务速度: 如果目的确实是在文件名中查找搜索词:
$searchWords = (Get-Content 'C:\temp\list.txt') -split ','
$path = 'C:\Users\david.craven\Dropbox\Facebook Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*'
Get-ChildItem -File -Path $path -Recurse -PipelineVariable file |
Select-Object -ExpandProperty Name |
Select-String -List -SimpleMatch -Pattern $searchWords |
Select-Object @{n='SearchWord'; e={$_.Pattern}},
@{n='FoundFile'; e={$file.FullName}} |
Export-Csv C:\temp\output.csv -NoTypeInformation
$searchWords = (Get-Content 'C:\temp\list.txt') -split ','
$path = 'C:\Users\david.craven\Dropbox\Facebook Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*'
Get-ChildItem -File -Path $path -Recurse |
Select-String -SimpleMatch -Pattern $searchWords |
Select-Object @{n='SearchWord'; e={$_.Pattern}},
@{n='FoundFile'; e={$_.Path}} |
Export-Csv C:\temp\output.csv -NoTypeInformation
如果目的是在文件内容中查找搜索词:
$searchWords = (Get-Content 'C:\temp\list.txt') -split ','
$path = 'C:\Users\david.craven\Dropbox\Facebook Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*'
Get-ChildItem -File -Path $path -Recurse -PipelineVariable file |
Select-Object -ExpandProperty Name |
Select-String -List -SimpleMatch -Pattern $searchWords |
Select-Object @{n='SearchWord'; e={$_.Pattern}},
@{n='FoundFile'; e={$file.FullName}} |
Export-Csv C:\temp\output.csv -NoTypeInformation
$searchWords = (Get-Content 'C:\temp\list.txt') -split ','
$path = 'C:\Users\david.craven\Dropbox\Facebook Asset Tagging\_SJC Warehouse_\_Project Completed_\2018\A*'
Get-ChildItem -File -Path $path -Recurse |
Select-String -SimpleMatch -Pattern $searchWords |
Select-Object @{n='SearchWord'; e={$_.Pattern}},
@{n='FoundFile'; e={$_.Path}} |
Export-Csv C:\temp\output.csv -NoTypeInformation
提高绩效的关键:
- 通过将所有搜索词传递给
,使用单个命令执行搜索Select String
- 与其在脚本块中使用
和新对象
构造自定义对象,不如让添加成员
直接在管道中使用来构造对象选择对象
- 与使用
迭代构建中间数组(每次都在幕后重新创建数组)不同,使用单个管道将结果对象直接传输到+=
导出Csv
addmember
cmdlet的速度会非常慢,因此通过将哈希表转换为[PSCustomObject]类型的加速器来切换这种方法:
[PSCustomObject]@{
SearchWord = $Word
File = $File.FullName
}
此外,没有理由预先创建一个数组对象,然后将每个文件添加到其中。您可以简单地在变量中捕获foreach循环的输出:
$Results = Foreach ($Word in $Words)
{
...
因此,更快的循环可能如下所示:
$Words = Get-Content -Path $WordList
$Files = Get-ChildItem -Path $Path -Recurse -File
$Results = Foreach ($Word in $Words)
{
foreach ($File in $Files)
{
if ($File.BaseName -match $Word)
{
[PSCustomObject]@{
SearchWord = $Word
File = $File.FullName
}
}
}
}
更简单的方法可能是使用文件数组上的Where对象:
$Results = Foreach ($Word in $Words)
{
$Files | Where-Object BaseName -match $Word
}
同时尝试这两种方法并测试性能。因此,如果加速循环不能满足您的需要,请尝试完全删除循环。您可以使用regex并将所有单词连接在一起:
$Words = Get-Content -Path $WordList
$Files = Get-ChildItem -Path $Path -Recurse -File
$WordRegex = $Words -join '|'
$Files | Where basename -match $WordRegex
您是否试图从文件内容中查找
$sw
?这个问题听起来很像,但脚本只显示文件名。您阅读了全部1100个文件,每400个单词都在查找!这种疯狂的语言能一次搜索10个单词吗?然后,您只需要对1100个文件进行40次传递,速度将提高10倍。如果你找到了一个号码,你需要继续搜索文档吗?或者你能在第一次匹配时退出吗?这种疯狂的语言允许并行化吗?你能用Linux来代替这个东西吗?看看,哪个可以使用正则表达式进行更有效的匹配。此外,与多次调用getchilditem
相比,您可能更高效地先获取所有文件名,然后在内存中检查它们。最后,尝试使用该方法,而不是新建对象
/添加成员
,因为管道可能会减慢速度。@MarkSetchell当然select string
类似于powershell中的grep
,它可以搜索多个模式以及regexIf如果您有项目中的一段工作代码,并且正在寻找以下领域的开放式反馈:最佳实践和设计模式使用、安全问题、*性能*,在未预料到的情况下保持正确性-然后是提出问题的正确地方。有人能提出这个问题吗?我不能。太好了!我总是忘记-PipelineVariable!谢谢,@MattMcNabb。这是一个方便的特性,但是对它的需求并不经常出现,所以很难记住。谢谢@MattMcNabb的精彩解释。不幸的是,我看到了下面的错误<代码>选择字符串:无法将参数绑定到参数“模式”,因为它是空字符串。在C:\Users\david.craven\Downloads\test.ps1:5 char:39+选择字符串-SimpleMatch-模式$searchWords |+~~~~~~~~~~~~~~~~~~~~~~+CategoryInfo:InvalidData:(:)[选择字符串],参数Bindin gValidationException+FullyQualifiedErrorId:ParameterArgumentValidationErrorEmptyStringNotAll owed,Microsoft.PowerShell.Commands.SelectStringCommand@dcraven:这表明$searchWords
是空的,而不是包含您的搜索词。多个匹配项的优点是,@LotPings。为了简单起见,我决定将-List
添加到Select String
,这将匹配限制为最多出现一次。