我对如何编写搜索文件系统以查找与主CSV文件中包含的任何条目匹配的文件的一些想法感兴趣。我有一个搜索文件系统的功能,但是对CSV的过滤比我预期的更难。我有一个带有标题的csv用于Name& IPaddr的:
#create CSV object
$csv = import-csv filename.csv
#create filter object containing only Name column
$filter = $csv | select-object Name
#Now run the search function
SearchSubfolders | where {$_.name -match $filter} #returns no results
我想我的问题是这样的:我可以过滤像这样的管道中的数组吗?
答案 0 :(得分:1)
你需要一对循环:
#create CSV object
$csv = import-csv filename.csv
#Now run the search function
#loop through the folders
foreach ($folder in (SearchSubfolders)) {
#check that folder against each item in the csv filter list
#this sets up the loop
foreach ($Filter in $csv.Name) {
#and this does the checking and outputs anything that is matched
If ($folder.name -match $Filter) { "$filter" }
}
}
答案 1 :(得分:0)
通常,CSV是二维数据结构,因此您无法直接使用它们进行过滤。但是,您可以将二维数组转换为一维数组:
$filter = Import-Csv 'C:\path\to\some.csv' | % {
$_.PSObject.Properties | % { $_.Value }
}
如果CSV只有一列,则可以将“mangling”简化为此(将Name
替换为实际列名称):
$filter = Import-Csv 'C:\path\to\some.csv' | % { $_.Name }
或者这个:
$filter = Import-Csv 'C:\path\to\some.csv' | select -Expand Name
当然,如果CSV只有一个列,那么最好立即将其设为一个平面列表,因此它可以像这样导入:
$filter = Get-Content 'C:\path\to\some.txt'
无论哪种方式,准备好$filter
,您都可以将其应用于输入数据,如下所示:
SearchSubFolders | ? { $filter -contains $_.Name } # ARRAY -contains VALUE
-match
运算符不起作用,因为它将值(左操作数)与正则表达式(右操作数)进行比较。
有关详细信息,请参阅Get-Help about_Comparison_Operators
。
答案 2 :(得分:0)
另一种选择是从文件名集合创建一个正则表达式,并使用它来一次过滤所有文件名:
$filenames = import-csv filename.csv |
foreach { $_.name }
[regex]$filename_regex = ‘(?i)^(‘ + (($filenames | foreach {[regex]::escape($_)}) –join “|”) + ‘)$’
$SearchSubfolders |
where { $_.name -match $filename_regex }
答案 3 :(得分:0)
如果要将文件的实际名称与列表中的名称相匹配,则可以使用Compare-Object
来轻松完成此操作。一个例子:
$filter = import-csv files.csv
ls | Compare-Object -ReferenceObject $filter -IncludeEqual -ExcludeDifferent -Property Name
这将打印当前目录中与Name
中的任何files.csv
匹配的文件。您也可以通过删除-IncludeEqual
和-ExcludeDifferent
标记来仅打印不同的标记。如果你需要完整的正则表达式匹配,你将需要遍历csv中的每个正则表达式并查看它是否匹配。
这是使用正则表达式过滤器的任何替代解决方案。请注意,我们将创建和缓存正则表达式实例,因此我们不必依赖运行时的内部缓存(默认为15个项目)。首先,我们有一个有用的辅助函数Test-Any
,它将循环遍历一个项目数组,并在其中任何一个满足条件时停止:
function Test-Any() {
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
[object[]]$Items,
[Parameter(Mandatory=$True,Position=2)]
[ScriptBlock]$Predicate)
begin {
$any = $false
}
process {
foreach($item in $items) {
if ($predicate.Invoke($item)) {
$any = $true
break
}
}
}
end { $any }
}
有了这个,实现相对简单:
$filters = import-csv files.csv | foreach { [regex]$_.Name }
ls -recurse | where { $name = $_.Name; $filters | Test-Any { $_.IsMatch($name) } }
答案 4 :(得分:0)
我最终使用了'循环中的'循环'构造,在经过多次试验和错误后完成了这项工作:
#the SearchSubFolders function was amended to force results in a variable, SearchResults
$SearchResults2 = @()
foreach ($result in $SearchResults){
foreach ($line in $filter){
if ($result -match $line){
$SearchResults2 += $result
}
}
}
将CSV文件折叠到基于文本的数组后,这种方法很有用,该数组只包含该CSV中必要的列数据。非常感谢Ansgar Wiechers协助我完成这件事!
所有人都提出了可行的解决方案,有些比我更关心,但如果我能将多个答案标记为正确,我会!我选择的正确答案不仅基于正确性而且还基于简单性......