在 Get-ChildItem 中指定 *.xls 过滤器也会返回 *.xlsx 结果 [英] Specifying *.xls filter in Get-ChildItem also returns *.xlsx results

查看:59
本文介绍了在 Get-ChildItem 中指定 *.xls 过滤器也会返回 *.xlsx 结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含 .xls、.xlsx 和 .xlsm 文件的文件夹,我只想过滤 .xls 文件.

为什么以下行没有像我期望的那样工作?我看到 .xls、.xlsx 和 .xlsm 结果.

Get-ChildItem $(Get-Location) -Filter *.xls |ForEach-Object { $_.Extension }

解决方案

-Filter 参数的通配符匹配由 PowerShell 执行,它被传递给文件系统提供者,最终传递给 Windows API.在那里进行的匹配受到许多遗留行为和怪癖的影响,包括您所看到的:

  • Windows PowerShell 中,-Filter *.xls 的行为类似于 -Filter *.xls*.因此,例如,-Filter *.xls 匹配 foo.xlsfoo.xlsx;发生这种情况是因为8.3(短)文件名在幕后匹配;例如,foo.xlsx 的 8.3 文件名看起来像 FOO~1.XLS;注意 .xlsx.XLS 的截断(和大写).

  • 虽然 短名称匹配行为在 PowerShell [Core] v6+ 中不再发生,但幸运的是,其他遗留问题仍然存在[1],以及最显着的区别(不会消失):PowerShell 通配符表达式(请参阅 about_Wildcards) 支持字符范围/集通过 [...](例如,[az]) - -Filter 不支持它们.

  • 使用 -Filter 参数通常比 -Path/-Include 更可取>(见下文)由于其卓越的性能(过滤发生在源头,而不是事后在 PowerShell 中).

解决方法是使用 -Path 参数,以便使用 PowerShell 的 通配符匹配:

Get-ChildItem -Path (Join-Path (Get-Location) *.xls) |ForEach-Object { $_.Extension }# 或者,更简单Get-ChildItem -Path $PWD/*.xls |ForEach-Object 扩展

注意:如果使用 -Recurse,您将改用 -Include 参数.

<小时>

[1] 其他值得注意的怪癖:

  • 多个连续的 ? 通配符可以匹配较少个字符的名称.

    • 例如,Get-ChildItem -Filter ??.txt 匹配 aa.txt 并且意外地也匹配 a.txt
    • 注意:这在 PowerShell Core 6.x 中暂时修复(从 6.2.3 开始),但从 PowerShell Core 7.0.0-rc.2 开始,该行为又恢复了
  • 模式 *. 匹配无扩展名的文件和目录名称.

    • 例如,Get-ChildItem -File -Filter *. 查找名称没有扩展名(例如,-File)的所有文件(-File)>文件);这个怪癖实际上很有用,因为它是定位无扩展名文件的最简单和性能最好的方法(-Path *. 确实不起作用,因为它看起来对于以 . 结尾的文件名字面意义.

    • 注意:这在 PowerShell Core 6.x(自 6.2.3 起)中暂时发生了变化,但该行为从 PowerShell Core 7.0 起又恢复了.

      立>
  • 相反,*.* 也包括无扩展名的文件和目录名称.

请参阅这个出色的答案">Zenexer 了解背景故事和血腥细节.

I have a folder that contains both .xls, .xlsx and .xlsm files, and would like to filter just the .xls files.

Why is the following line not working as I'd expect it to? I see .xls, .xlsx and .xlsm results.

Get-ChildItem $(Get-Location) -Filter *.xls | ForEach-Object { $_.Extension }

解决方案

The -Filter parameter's wildcard matching is not performed by PowerShell, it is passed through to the filesystem provider and ultimately the Windows API. The matching performed there is burdened with many legacy behaviors and quirks, including the one you saw:

  • In Windows PowerShell, -Filter *.xls effectively behaves like -Filter *.xls*. Therefore, -Filter *.xls matches both foo.xls and foo.xlsx, for instance; this happens, because the 8.3 (short) file names are also being matched behind the scenes; for instance, foo.xlsx's 8.3 file name looks something like FOO~1.XLS; note the truncation (and capitalization) of .xlsx to .XLS.

  • While the short-name matching behavior no longer occurs in PowerShell [Core] v6+, fortunately, other legacy quirks persist[1], as does the most notable difference (which won't go away): only PowerShell wildcard expressions (see about_Wildcards) support character ranges / sets via [...] (e.g., [a-z]) - they're not supported with -Filter.

  • Use of the -Filter parameter is in general still preferable to -Path / -Include (see below) due to its superior performance (filtering happens at the source, instead of after the fact in PowerShell).

The workaround is to use the -Path parameter in order to use PowerShell's wildcard matching:

Get-ChildItem -Path (Join-Path (Get-Location) *.xls) | ForEach-Object { $_.Extension }

# Or, more simply
Get-ChildItem -Path $PWD/*.xls | ForEach-Object Extension

Note: With -Recurse you'd use the -Include parameter instead.


[1] Notable other quirks:

  • Multiple consecutive ? wildcards can match names with fewer characters.

    • E.g., Get-ChildItem -Filter ??.txt matches aa.txt and unexpectedly also a.txt
    • Note: This was temporarily fixed in PowerShell Core 6.x (as of 6.2.3), but the behavior is back as of PowerShell Core 7.0.0-rc.2
  • Pattern *. matches extension-less file and directory names.

    • E.g., Get-ChildItem -File -Filter *. finds all files (-File) whose names do not have an extension (e.g., file); this quirk can actually be useful, in that it is the simplest and best-performing way to locate extension-less files (-Path *. does not work, because it looks for a file name literally ending in a .).

    • Note: This was temporarily changed in PowerShell Core 6.x (as of 6.2.3), but the behavior is back as of PowerShell Core 7.0.

  • Conversely, *.* includes extension-less file and directory names as well.

See this excellent answer by Zenexer for the backstory and the gory details.

这篇关于在 Get-ChildItem 中指定 *.xls 过滤器也会返回 *.xlsx 结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆