这个问题的根源在于递归的误用与过滤的结合。我将通过一些例子来说明。首先我们应该建立一个示例目录结构:
mkdir Temp
mkdir Temp\bin
mkdir Temp\obj
mkdir Temp\node_modules
mkdir Temp\node_modules\bin
mkdir Temp\node_modules\obj
Out-File .\Temp\Readme.md
Out-File .\Temp\bin\Readme.md
Out-File .\Temp\obj\Readme.md
Out-File .\Temp\node_modules\Readme.md
Out-File .\Temp\node_modules\bin\Readme.md
Out-File .\Temp\node_modules\obj\Readme.md
cd .\Temp\
让我们尝试一些示例。我会将Get-ChildItem 的内容通过管道传输到Select-Object,以更好地说明我们正在检索的内容。首先,香草Get-ChildItem:
PS C:\Temp> Get-ChildItem | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\node_modules
C:\Temp\obj
C:\Temp\Readme.md
这会返回我们所期望的,相当于dir。现在,让我们尝试使用-Include 来仅“包含”bin 文件夹。
PS C:\Temp> Get-ChildItem -Include bin | Select-Object FullName
PS C:\Temp>
嗯。它什么也没返回...我们认为它会列出所有内容,并且“仅”包括 bin 文件夹。相反,它所做的是将命令解释为“无”的Get-ChildItem(因为我们没有指定要获取的任何文件)和“无”的“包含”,即模式bin。这是有道理的,并且在Docs 中列出了“Include 需要 Path 参数”。行。让我们更改它以实际获取所有内容*然后执行-Include bin,然后我们应该得到我们想要的......对吗?
PS C:\Temp> Get-ChildItem * -Include bin | Select-Object FullName
PS C:\Temp>
胡?我认为使用通配符,它会包含bin 文件夹,对吗?这不是它的工作原理吗?....不完全是。让我们把它改成-Include一个文件而不是一个目录:
PS C:\Temp> Get-ChildItem * -Include Readme.md | Select-Object FullName
FullName
--------
C:\Temp\Readme.md
所以它看起来像显式过滤,带有通配符的是 files 而不是 directories。那么原始示例(我们包含目录的位置)如何工作?...嗯,这是因为-Recurse 的工作方式不同。 -Recurse 改变了我们得到的东西,它返回 everything 所以Include 工作:
PS C:\Temp> Get-ChildItem -Include bin -Recurse | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\node_modules\bin
在此示例中,当我们不必指定通配符 * 过滤器时,-Recurse 会隐式地从目录中获取所有内容。注意:它包括与名称 bin 匹配的目录。另外,请注意,它不包含目录中的文件。
为什么示例 1:
gci -include bin,obj -recurse | remove-item -force -recurse
有效是因为 Get-ChildItem 返回目录,而 Remove-Item 与 -Force 和 -Recurse 负责删除文件。
为了证明没有什么奇怪的事情发生,让我们做一个-Exclude node_modules:
PS C:\Temp> Get-ChildItem -Exclude node_modules -Recurse | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\bin\Readme.md
C:\Temp\node_modules\bin
C:\Temp\node_modules\bin\Readme.md
C:\Temp\node_modules\obj
C:\Temp\node_modules\obj\Readme.md
C:\Temp\node_modules\Readme.md
C:\Temp\obj
C:\Temp\obj\Readme.md
C:\Temp\Readme.md
嗯...返回的结果比预期的要多...但不是。请注意,它没有返回 C:\Temp\node_modules。这是因为-Exclude node_modules 是正确的。它排除了特别命名的文件夹:node_modules,并包括了其他所有内容。
这是第二个例子不起作用的原因:
gci -exclude node_modules -include bin,obj -recurse | remove-item -force -recurse
排除过滤器将排除名为node_modules 的特定文件夹,但由于-Recurse 将-Include 任何与bin 或obj 匹配的子文件夹。 当然,node_modules 有很多,因此不能按我们的意愿工作。
那么,如果-Include 不适用于目录,并且-Recurse 太深,那么@cResults 问题将如何解决?好吧,与其乱用过滤器,不如像往常一样简单地询问我们想要的文件夹?
PS C:\Temp> Get-ChildItem bin,obj | Select-Object FullName
FullName
--------
C:\Temp\bin\Readme.md
C:\Temp\obj\Readme.md
这没关系,它返回文件夹的内容,就像前面的例子一样,子项而不是目录......好吧,我们真正想要的是文件夹项所以我们使用Get-ChildItem而不是Get-Item:
PS C:\Temp> Get-Item bin,obj | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\obj
现在,切换到Get-Item 后,我们得到了文件夹,而不是文件夹中的子项,我们现在可以将其与Remove-Item 一起使用,它会负责其余的工作:
Get-Item bin,obj | Remove-Item -Force -Recurse