在PowerShell中,使用-Recurse参数时Get-ChildItem -Exclude无法正常工作。

3

enter image description here我想要递归搜索所有目录,但不包括以_(下划线)开头的目录。

例如:_archive_DO_NOT_DELETE_processing等。

我使用了下面的代码,但它没有起作用。看起来排除将不会与递归一起工作。有什么想法吗?

$exclude = @("_*")
$source = "C:\code\Powershell\delete empty folders\New folder\" 
$allitems = Get-ChildItem $source -Directory -Exclude $exclude -Recurse
foreach($myItem in $allitems)
{
  echo $myItem.fullname
} 

输出:

C:\code\Powershell\delete empty folders\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (2)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)\New folder
C:\code\Powershell\delete empty folders\New folder\_archive\New folder

因此,如我之前所说,我想要避免以下划线开头的目录,因此最后一行不应出现。

即使我也使用了以下代码,输出结果仍然相同:

$exclude = @("_*")
$source = "C:\code\Powershell\delete empty folders\New folder\"
$allitems = Get-ChildItem $source -Recurse -Directory |
            Where {$_.FullName -notlike $exclude}
foreach($myItem in $allitems)
{
    echo $myItem.fullname
}

@Paxz -exclude开关接受数组。例如,-exclude "*.txt","*.log"是有效的语法。 - vonPryz
@vonPryz 是的,我也注意到了。 - Paxz
我也尝试过使用“-exclude“ _*”,其实两种方法都一样。@Paxz,提供给你我的信息,在我的情况下,如果我删除“-recurse”,那么排除部分就会生效。 - Tanmoy De
1
空格是否有意?\_archive 还是 \_archive - vonPryz
排除(exclude)的问题在于它只作用于路径结构上的叶子节点。 - Luiz Felipe
显示剩余2条评论
3个回答

4
这里发生的情况是,Get-ChildItem的-exclude参数基于项目的名称属性工作。当使用通配符时,名称必须与非通配符部分匹配。但在目录名称以空格开头时,就不会发生这种情况。让我们看一个例子:
# Create two files, one starts with a space, the other doesn't
Set-Content -Path " data1.txt" -Value $null
Set-Content -Path "data2.txt" -Value $null

gci -name "data*"
 data2.txt

gci -name " data*"
 data1.txt

结果只匹配了一个通配符。原因是data1.txt的第一个字符是空格,而不是参数d的第一个字符。 -exclude参数往往比较棘手。更容易通过将结果管道传递给where-object来解决。如下所示:
Get-ChildItem $source -Directory -recurse | ? {$_.fullname -NotMatch "\\\s*_"} | % { $_.fullname }
# "\\\s*_" is regex for \, any amount of whitespace, _ 
C:\code\Powershell\delete empty folders\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (2)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)\New folder

Get-ChildItem $source -Directory -recurse | ? {$_.fullname -Match "\\\s*_"} | % { $_.fullname }
C:\code\Powershell\delete empty folders\New folder\ _archive
C:\code\Powershell\delete empty folders\New folder\ _archive\New folder

请注意,匹配需要评估 FullName 属性。仅使用 Name 将仅匹配叶级别。

我的错!!空格不在那里,目录名只是“_archive”。 - Tanmoy De

2

第一次尝试并没有找到答案。但是如果您想使用Where-Object,您需要将过滤器从_*更改为*_*

这是因为.Fullname显示完整路径,因此在实际路径的_之前有很多字符。

$exclude = @("*_*")
$source = "C:\code\Powershell\delete empty folders\New folder\"
$allitems = Get-ChildItem $source -Recurse -Directory | Where {$_.FullName -notlike $exclude}
$allitems.Fullname

应该会给您期望的输出结果。

我的错!!空格不在那里,目录名只是“_archive”。 - Tanmoy De
如果需要多个排除过滤器,请不要使用此方法,因其无法处理多个过滤器。可以尝试以下代码:Get-ChildItem $source -Directory -Recurse | Where-Object { $_.FullName | Select-String -SimpleMatch -NotMatch $xclds } - Luiz Felipe

2
如评论中@Paxz所说,该命令已按照预期运行,只是不符合你的希望。它确实从输出中排除了以_开头的文件夹,但这不适用于-Recurse选项,因此它仍会搜索那些文件夹中的其他项,并显示它们(如果它们的名称不以_开头)。
您可以使用自己的过滤器来获取您想要的内容:
Get-ChildItem -Path $source -Directory -recurse |
    Where-Object {$_.FullName -notlike "*\_*"} |
        Format-Table FullName

请注意,这仍然可以找到所有带有 _ 的文件夹,但只是丢弃它们(因此没有性能提升)。此外,使用更简单的过滤器:-notlike "*_*" 将排除任何名称中间或结尾带有下划线的文件夹(例如 Hello_World),而不仅仅是开头。

1
@Paxz,嗯...不是故意的。我尝试编辑它,可能出了些问题。我已经删除了重复内容。 - boxdog
我的错!!空格不在那里,目录名只是“_archive”。 - Tanmoy De

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