使用Array按名称过滤文件

时间:2017-02-10 22:11:34

标签: powershell powershell-v2.0

我正在尝试查找文件夹中与数组中的任何条目匹配的所有文件,以便我可以将它们移动到另一个文件以用于组织。我可以在这里使用PowerShell 2.0;我不确定这是不是让我失望,我在学校学习了PowerShell 4.0。

# Declared variables & array
$files = get-childitem "Y:\Downloads\"
$start = "Y:\Downloads\"
$end = "Y:\Downloads\sorted"
$fileEXT = "*.jokes.*","*.laughter.*","*.comedy.*","*.humour.*"

# Moving Files

#foreach ($file in $files) {
#  if ($file.Name -contains $fileEXT[0-9]) {
#    Move-Item $start $end
#  }
#}

foreach ($element in $fileEXT) {
  if ($files.Name -contains $element) {
    Move-Item $start $end
  }
}

#$start | Where-Object { $fileEXT -contains $_.Name } | Move-Item to $end

2 个答案:

答案 0 :(得分:0)

试试这个(别忘了删除-whatif)

注意:

- $_.Base contains file name without extension
- use !$_.PSIsContainer for take only files

代码:

$fileEXT = "test","laughter","comedy","humour"
$start = "Y:\Downloads\"
$end   = "Y:\Downloads\sorted"

#solution 1
Get-ChildItem $start | where {$Name=$_.BaseName; !$_.psiscontainer -and  ($fileEXT | where {$name -like "*$_*"}).Count -gt 0 } | 
move-item -Destination $end -WhatIf

#solution 1b (powershell 3)
Get-ChildItem $start -file | where {$Name=$_.BaseName; ($fileEXT | where {$name -like "*$_*"}).Count -gt 0 } |
move-item -Destination $end -WhatIf

#Solution 2 with regex
$fileEXT = "test|laughter|comedy|humour"
Get-ChildItem $start | where {!$_.psiscontainer -and  $_.BaseName -match $fileEXT} | 
move-item -Destination $end -WhatIf

#Solution 2b with regex (powershell 3), better solution gived by @TessellatingHeckler
$fileEXT = "test|laughter|comedy|humour"
Get-ChildItem $start -file | where { $_.BaseName -match $fileEXT} |
move-item -Destination $end -WhatIf

答案 1 :(得分:0)

与提到的@BenH一样,您使用的是错误的运算符。 -contains运算符允许您检查数组是否包含特定值(不是值的一部分):

'ab', 'cd', 'ef' -contains 'cd'    # returns true
'ab', 'cd', 'ef' -contains 'c'     # returns false

您可能会将运算符与String.Contains()方法混淆,后者允许您检查字符串是否包含特定的子字符串:

'abcdef'.Contains('cd')

但是,它们都不允许检查字符串是否包含任何子字符串列表。您的方法需要两个循环,因为您需要将每个文件与每个过滤器元素进行比较,并且需要使用-like运算符进行通配符比较。来自内循环的Break因此,如果项目与多个过滤元素匹配,则不要尝试移动项目两次。

foreach ($file in $files) {
  foreach ($element in $fileEXT){
    if ($file.Name -like $element){
      Move-Item $file.FullName $end
      break
    }
  }
}

但是,使用嵌套循环将两个数组相互比较并不会很好。更好的方法是将搜索项放在数组中并从中构造regular expression,这样就可以一次性检查所有过滤元素:

$words = 'jokes', 'laughter', 'comedy', 'humour'
$re    = '\.(' + ($words -join '|') + ')\.'

Get-ChildItem 'Y:\Downloads' |
  Where-Object { $_.Name -match $re } |
  Move-Item -Destination 'Y:\Downloads\sorted'

作为旁注,虽然您可以使用单个字符串定义正则表达式,但我不建议这样做。除非你打算这是一个一次性的脚本(也许甚至不是那样)。

$re = '\.(jokes|laughter|comedy|humour)\.'   # don't do this

使$words数组并加入数组以形成实际的正则表达式使维护更容易,并允许您将单词放在单独的文件中(与代码分开的数据):

jokes
laughter
comedy
humour

让你的脚本读取该文件:

$words = Get-Content 'C:\wordlist.txt'