我有一个包含 .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.xls
和foo.xlsx
;发生这种情况是因为8.3(短)文件名也在幕后进行匹配;例如,foo.xlsx
的 8.3 文件名类似于FOO~1.XLS
;请注意.xlsx
到.XLS
的截断(和大写)。虽然 PowerShell [Core] v6+ 中不再出现短名称匹配行为,但幸运的是,其他遗留问题依然存在[1],最显着的区别(不会消失):仅 PowerShell 通配符表达式(请参阅
about_Wildcards
)支持字符范围/通过[...]
设置(例如[a-z]
) --Filter
不支持它们。使用
-Filter
参数通常仍然优于-Path
/-Include
(见下文)由于其卓越的性能(过滤发生在源头,而不是事后在 PowerShell 中进行)。
解决方法是使用 -Path
参数,以便使用 PowerShell 的通配符匹配:
Get-ChildItem -Path (Join-Path (Get-Location) *.xls) | ForEach-Object { $_.Extension }
# Or, more simply
Get-ChildItem -Path $PWD/*.xls | ForEach-Object Extension
注意:使用 -Recurse
时,您可以使用 -Include
参数; 如果没有-Recurse
,-Include
(和-Exclude
)的行为不直观,不幸的是 - 请参阅 this answer 的底部部分.
[1]其他值得注意的怪癖:
多个连续的
?
通配符可以匹配具有更少个字符的名称。- 例如,
Get-ChildItem -Filter ??.txt
匹配aa.txt
并且意外地也匹配a.txt
- 例如,
模式
*.
匹配无扩展名的文件和目录名称。例如,
Get-ChildItem -File -Filter *.
查找名称没有扩展名的所有文件 (-File
)(例如文件
);这个怪癖实际上很有用,因为它是定位无扩展名文件的最简单且性能最好的方法(-Path *.
确实不起作用,因为它看起来对于以.
结尾的文件名。注意:这在 PowerShell Core 6.x 中暂时发生了变化(自 6.2.3 起),但该行为自 PowerShell Core 7.0 起又恢复了。
相反,
*.*
也包括无扩展名的文件和目录名称。
参见this excellent answer通过 Zenexer了解背景故事和血淋淋的细节。
关于powershell - 在 Get-ChildItem 中指定 *.xls 过滤器也会返回 *.xlsx 结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60171057/