在PowerShell中排除目录

26

我希望在PowerShell中排除所有目录的搜索。无论是 FileInfo 还是 DirectoryInfo 都包含了 Attributes 属性,这似乎正是我想要的,但我找不到如何基于它进行过滤的方法。

ls | ? { $_.Attributes -ne 'Direcory' }
ls | ? { $_.Attributes -notcontains 'Direcory' }

没用。我该怎么做?


旁注:应该是“Directory”。然后两者都适用于没有设置任何其他属性(如ReparsePoint)的目录。 - Joey
是的,你说得对。这是一个愚蠢的错误。 - svick
4个回答

25
您可以使用PSIsContainer属性:
gci | ? { !$_.PSIsContainer }

你的方法也可以运行,但是需要像这样:

gci | ? { !($_.Attributes -band [IO.FileAttributes]::Directory) }

由于属性是枚举和位掩码,因此可以这样做。

或者,对于您的其他方法:

gci | ? { "$($_.Attributes)" -notmatch "Directory" }

这将导致属性被转换为一个字符串(可能看起来像“Directory, ReparsePoint”),而在一个字符串上你可以使用-notmatch运算符。

PowerShell v3终于在Get-ChildItem上拥有了-Directory参数:

Get-ChildItem -Directory
gci -ad

似乎仅使用LS不起作用?*PS:D:\batch> (ls d:\batch -Recurse -File .ps1).count 550 - Patrick Burwell
虽然我试图排除一个文件夹失败了 (ls d:\batch -Recurse -File .ps1 -Exclude 'D:\batch\foldertoexclude*.ps1').count 仍然显示550 (实际的foldertoexclude路径为 "D:\batch\foldertoexclude*.ps1",但在这里的形式会删除单引号内'.ps1'前面的 ''...好奇怪,对吧?...) 哦,哇,即使在双引号内也是如此" LOL! 'D:\batch\foldertoexclude*.ps1' - Patrick Burwell

11

在PowerShell中排除目录:

Get-ChildItem | Where-Object {$_ -isnot [IO.DirectoryInfo]}

或者更简洁,但难以阅读的版本:

gci | ? {$_ -isnot [io.directoryinfo]}
Credit goes to @Joey for his insightful comment using the -is operator :)
However Technically, I prefer including only Files or only Directories since excluding can lead to unexpected results as Get-ChildItem can return more than just files and directories :)
Include just Files:
Get-ChildItem | Where-Object {$_ -is [IO.FileInfo]}

或者:

gci | ? {$_ -is [io.fileinfo]}

仅包括目录:

Get-ChildItem | Where-Object {$_ -is [IO.DirectoryInfo]}

或者:

gci | ? {$_ -is [io.directoryinfo]}

6
你可以通过直接查看目录的类型来过滤掉它们:
ls | ?{$_.GetType() -ne [System.IO.DirectoryInfo]}

使用get-childitem(或ls或dir)返回类型为System.IO.DirectoryInfo的目录,并且文件的类型为System.IO.FileInfo。在PowerShell中将这些类型作为文字字面值使用时,需要将它们放在括号中。


4
顺便提一下,您可以使用-is运算符来实现这一点。因此,它可以简写为:gci | ? {$_ -is [IO.FileInfo]} - Joey
1
当然,使用这种方法您仅限于文件系统提供程序,而PsIsContainer应该适用于任何存在容器概念的提供程序。 - EBGreen
应该考虑使用-is运算符。是的,FileInfo仅适用于文件系统。 - Anton I. Sipos

0

不同方法的时间,短目录下5000次迭代和System32目录下25次迭代的时间。测量使用以下工具:

(measure-command { for ($i=0;$i -lt 5e3;$i++) {       
  $files= gci | ? { !$_.PSIsContainer }   # this is target to measure
} } ).totalmilliseconds

从最慢到最快的结果(所有行的最终结果相同):

$files= gi *.* | ? { !$_.PSIsContainer }  #5000 iterations / 25long = 15.2sec / 22s
$files= foreach ($file in gi *.*) { if ($file.mode -notmatch 'd') { $file } }   # 11.8s / 20s
$files= gci | ? { !($_.Attributes -band [IO.FileAttributes]::Directory) }  # 8.9s  /  10.7s
$files= Get-ChildItem | Where-Object {$_.mode -notmatch 'd'}  # 8.8s  / 10.6s
$files= gci | ? { !$_.PSIsContainer }  # 7.8s  / 9.8s
$files= Get-ChildItem | ? {$_ -isnot [IO.DirectoryInfo]}  # 7.6s  /  9.6s
$files= gci | Where-Object {$_ -is [IO.FileInfo]}  # 7.6s  / 9.6s
$files= foreach ($file in gci *.*) { if ($file.mode -notmatch 'd') { $file } }    #7.3s  / 12.4s
$files= @( foreach ($file in gci) { if ($file.mode -notmatch 'd') { $file } } ) #3.7s  /  6.4s
$files= foreach ($file in gci) { if ($file.mode -notmatch 'd') { $file } }  # 3.7s  /  6.4s

请注意,指定“*.*”将几乎使处理时间增加一倍。这就是为什么没有参数的GCI比必须使用*.*参数的GI更快的原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接