使用数组按名称过滤文件

Filter files by name with an Array

我试图在文件夹中查找与数组中的任何条目匹配的所有文件,以便我可以将它们移动到不同的文件以进行组织。我在这里可以使用 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

试试这个(不要忘记删除 -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

Like mentioned, you're using the wrong operator. The -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'

附带说明一下,虽然您可以使用单个字符串定义正则表达式,但我不建议这样做。除非您打算将其作为 one-off 脚本(甚至可能不会)。

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

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

jokes
laughter
comedy
humour

并让您的脚本读取该文件:

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