【问题标题】:PowerShell - How to use multiple filter's with -not? (See example.)PowerShell - 如何将多个过滤器与 -not 一起使用? (参见示例。)
【发布时间】:2021-12-18 02:40:28
【问题描述】:

我正在尝试根据文件名中任何位置可能出现的文本移动 .pdf,但它不起作用。它执行没有错误,但不会移动文件。

文件名中带有“Sold”的所有 .pdf 文件都放在一个位置,文件名中没有“sold”的所有 .pdf 文件都放在另一个位置。

get-childitem -Recurse -path $sourcePathPDF  {-filter '*.pdf' -and '*Sold*'} | move-item -Destination $destinationPathSoldPDF 
get-childitem -Recurse -path $sourcePathPDF  {-filter '*.pdf' -not '*Sold*'} | move-item -Destination $destinationPathPDF 

我是否过滤/使用 -not 不正确?

感谢您的帮助。

【问题讨论】:

  • 你不需要-not,你需要-notlikeGet-ChildItem -Recurse |Where-Object { $_.Name -like '*.pdf' -and $_.Name -notlike '*Sold*'}

标签: powershell


【解决方案1】:
  • -Filter 只接受 single 模式。

  • 改用-Include-Exclude[1],这两者接受多个模式 .

# Two inclusion patterns
Get-ChildItem -Recurse -Path $sourcePathPDF -Include *.pdf, *sold*

# One inclusion, one exclusion pattern.
Get-ChildItem -Recurse -Path $sourcePathPDF -Include *.pdf -Exclude *Sold*

注意

  • 从 PowerShell 7.2 开始,-Include-Exclude 受到性能问题的阻碍,正如 Mathias R. Jessen 所指出的,由于它们的实施效率低下(请参阅GitHub issue #8662),因此下面讨论的基于Where-Object 的解决方案不仅可以用于更复杂的匹配逻辑,还可以用于性能。

  • -Include-Exclude 使用 PowerShell 的 wildcard expressions,它们具有更多功能,但缺少 -Filter 支持的平台原生模式的传统怪癖 - 有关详细信息,请参阅 this answer

    • 使用-Filter优点是它-Include / -Exclude 快得多,因为-Filter 在源头过滤,而@987654347 @ / -Exclude 过滤器在事实之后应用,通过PowerShell,在所有项首先被检索到之后。
  • 如果没有 -Recurse-Include-Exclude 将无法正常工作 - 请改用 Get-Item * -Include/-Exclude ... - 请参阅 this answer


为了更复杂的模式匹配和/或更好的性能管道到Where-Object 调用,您可以在其脚本块中使用基于通配符的-like operator,正如马蒂亚斯所建议的那样;或者,为了更灵活的匹配,您可以使用基于正则表达式的-match operator。从评论中调整 Mathias 的 -like-based Where-Object 解决方案:

Get-ChildItem -Recurse  -Path $sourcePathPDF |
  Where-Object { $_.Name -like '*.pdf' -and $_.Name -notlike '*Sold*' }

对于(当前)最佳性能,您可以使用-Filter预过滤

Get-ChildItem -Recurse -Path $sourcePathPDF -Filter *.pdf |
  Where-Object { $_.Name -notlike '*Sold*' }

至于你尝试了什么

  • -Filter-Include-Excludestring 类型的 - 不支持将 script blocks ({ ... } 与任意表达式一起传递给它们。

    • 虽然管道绑定参数可以接受脚本块,以便动态根据手头的输入对象提供参数值(称为delay-bind script blocks的功能),这些参数都不支持这种绑定,因此传递脚本块不适用。
  • 在您的尝试中实际发生的是 stringified 版本的脚本块 {-filter '*.pdf' -and '*Sold*'} - 这是它的逐字内容(不包括 {}) - 位置绑定到-Filter参数。

    • 也就是说,您有效地传递了-Filter "-filter '*.pdf' -and '*Sold*'",可以预见它不会匹配任何文件,因为逐字 -filter '*.pdf' -and '*Sold*' 被用作模式。

[1] 请注意,您甚至可以 -Filter-Include / -Exclude 结合使用,在这种情况下,-Filter 参数首先应用 em>,在源头。由于 -Include-Exclude 当前的工作方式,这只有在输入路径以 \*-Recurse 结尾时才有意义 - 请参阅 this answer

【讨论】:

  • 可能值得注意的是,将-Recurse-Include/-Exclude 结合起来会产生a serious performance penalty,这比仅将所有文件系统项通过管道传输到Where-Object 更糟糕:)
  • 谢谢,@MathiasR.Jessen - 请查看我的更新。我不知道-Include-Exclude 实际上有多慢。虽然它们固有地,必然-Filter慢,但没有理由表明其性能比需要额外Where-Object调用后过滤的等效命令差.回购-Include-Exclude 已经有几个问题,但我会看看我是否能找到一个提出这个特定问题的问题 - 如果你碰巧知道一个,请告诉我。
  • 哇,谢谢两位。我不确定我是否见过@mklemento 这么好的答案模板。 “你尝试了什么”部分应该更频繁地包含在答案中,因为它有助于专门填补提问者的知识空白。干得好,感谢您的帮助!
  • @mklement0 LGTM!恐怕我还没有关注最重要的相关问题。我倾向于支持-Filter + ... |Where-Object 尽可能排除,(而不是将包含和排除逻辑移至Where-Object
  • @Mathias :) 将-FilterWhere-Object 重新组合:非常有意义(答案已经显示了一个示例)。
【解决方案2】:

使用 -not,由于运算符优先级,您需要括号(没有括号“-not $_.name”变为“False”):

get-childitem | where {$_.name -like '*.pdf' -and -not ($_.name -like '*Sold*')} 

您也可以通过一些速度进入 wmi(不包括 c:\users?):

Get-WmiObject CIM_DataFile -filter 'Drive="C:" and Extension="pdf" and 
  not name like "%Sold%" and path like "\\%"'

【讨论】:

    猜你喜欢
    • 2017-02-27
    • 1970-01-01
    • 2021-04-02
    • 2019-09-26
    • 2012-01-28
    • 2018-12-29
    • 2019-11-07
    • 1970-01-01
    • 2023-03-13
    相关资源
    最近更新 更多