【问题标题】:Powershell glob pattern matchingPowershell glob 模式匹配
【发布时间】:2022-01-18 04:07:25
【问题描述】:

我正在通过C:\ProgramFiles 查找名为log4j-core-x.y.z.jar 的jar 文件。我正在尝试匹配最后一位数字z,它可以是一位数或两位数(0-99)。我似乎无法获得正确的 glob 模式来完成此操作。

Code:

PS C:\Users\Administrator> Get-ChildItem -Path 'C:\Program Files\' -Filter log4j-core-*.*.[1-9][0-9].jar -Recurse -ErrorAction SilentlyContinue -Force | %{$_.FullName}

这不会产生任何结果,但是当我只使用所有通配符时,-Filter log4j-core-*.*.*.jar,我得到:

C:\Program Files\apache-log4j-2.16.0-bin\apache-log4j-2.16.0-bin\log4j-core-2.16.0-javadoc.jar
C:\Program Files\apache-log4j-2.16.0-bin\apache-log4j-2.16.0-bin\log4j-core-2.16.0-sources.jar
C:\Program Files\apache-log4j-2.16.0-bin\apache-log4j-2.16.0-bin\log4j-core-2.16.0-tests.jar
C:\Program Files\apache-log4j-2.16.0-bin\apache-log4j-2.16.0-bin\log4j-core-2.16.0.jar

我唯一关心的是C:\Program Files\apache-log4j-2.16.0-bin\apache-log4j-2.16.0-bin\log4j-core-2.16.0.jarlog4j-core-2.16.0.jar

【问题讨论】:

    标签: windows powershell glob


    【解决方案1】:

    -Filter 不支持使用 regexCharacter ranges 进行过滤,例如 [A-Z][0-9]。感谢mklement0 指出。

    来自Get-ChildItem官方文档的参数说明:

    过滤器字符串被传递给 .NET API 以枚举文件。 API 仅支持*? 通配符。

    试试这个:

    Get-ChildItem -Path 'C:\Program Files\' -Filter log4j-core-*.*.??.jar -Recurse -ErrorAction SilentlyContinue -Force |
    Where-Object {
        $_.Name -match '\.\d{1,2}\.jar$'
        # => Ends with a . followed by 1 or 2 digits and the .jar extension
    }
    

    【讨论】:

      【解决方案2】:

      Santiago Squarzon's helpful answer 提供了一个regex 辅助解决方案,该解决方案有可能执行比当前案例所需的更复杂的匹配。

      让我用基于您自己尝试的wildcard-based 解决方案来补充它:

      • -Filter 参数支持PowerShell的通配符语法;它只支持*? 作为通配符元字符(如圣地亚哥笔记),还支持字符范围/集合结构,例如[0-9]

        • 相反,-Filter 参数由平台的文件系统 API 解释,在 Windows 上还有一些遗留问题 - 请参阅 this answer

        • 也就是说,对于 -Filter 确实支持的模式,它的使用优于 -Include(见下文),因为它的性能要好得多,因为 在源头进行过滤。 p>

      • 相比之下,-Include 参数确实使用 PowerShell 的通配符,另外还支持 多种模式。

      与正则表达式不同,PowerShell 通配符语言中的字符范围/集合表达式支持重复(量词)逻辑并且只匹配一个字符每个(就像 ?any 单个字符所做的那样;* 是唯一隐式支持重复的元字符:零个或多个字符)。

      因此,[1-9][0-9] 正好匹配 2 个字符(数字),只匹配 一个 数字 ([0-9]) 需要 附加 图案:

      Get-ChildItem -Recurse 'C:\Program Files' -Include log4j-core-*.*.[0-9].jar, log4j-core-*.*.[1-9][0-9].jar -ErrorAction SilentlyContinue -Force | 
        ForEach-Object FullName
      

      注意事项

      • 使用-Include(或-Exclude没有-Recurse不会像预期的那样工作 - 请参阅this answer

      • 从 PowerShell 7.2 开始,将 -Recurse-Include 结合使用会因实现效率低下而出现性能问题 - 请参阅 GitHub issue #8662

      【讨论】: