【问题标题】:How to prevent recursion through node_modules for gci script如何防止通过 node_modules 进行 gci 脚本的递归
【发布时间】:2019-05-13 21:20:53
【问题描述】:

我发现了这个很棒的 powershell 脚本

gci -include bin,obj -recurse | remove-item -force -recurse

Chris Jthis answer的评论

我每天使用多次。

如果存在任何 node_modules 文件夹或其子文件夹,您如何防止它运行?

我尝试过各种版本的

gci -exclude node_modules -include bin,obj -recurse | remove-item -force -recurse

没有成功。

更新: 在阅读了@HAL9256 的信息丰富的答案后,我意识到我没有包含一个重要的要求。我在我的 git repo 的根目录下运行这个脚本。因此,它会遍历多个 C# 项目文件夹,删除所有项目的 bin 和 obj 文件夹。这只是必要的,因为 Visual Studio 2017 和 2019 解决方案 clean 不会删除所有内容,而且我们正在从框架转换为标准/核心的过程中,清理后有一些工件留在 bin 和/或 obj 文件夹中,导致事情发生通过 git 分支更改转换(可能从核心回到框架)给定项目时中断。

【问题讨论】:

  • 如果您运行的是 psv5.1,那么 - 我记得 - -Exclude 和 -Include` 仅适用于文件名,不适用于目录。所以解决这个问题的常用方法是使用事后过滤器,如 Where-Object.Where() 来排除不需要的项目。
  • 看来这并不完全正确,因为上面的第一个脚本使用 -include 和 bin 和 obj 目录。它会删除所有 bin 和 obj 文件夹。问题是我不希望它删除任何 node_modules 文件夹中的 bin 和 obj 文件夹。我将如何使用 Where-Object 或 .Where() 来实现这一目标?
  • 啊!这一定是在 win7 上与 ps5.1 的另一个行为差异。 [sigh ...] ///// for the fitler >>> $Collection | Where-Object {$_.DirectoryName -notmatch 'bin|obj'} 咧嘴]

标签: visual-studio powershell


【解决方案1】:

这个问题的根源在于递归的误用与过滤的结合。我将通过一些例子来说明。首先我们应该建立一个示例目录结构:

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 任何与binobj 匹配的子文件夹。 当然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

【讨论】:

  • 感谢您详尽而翔实的解释。您对该过程的分解和说明极大地提高了我对我一直信任的代码实际工作方式的理解。在阅读您的答案之前,我已对未包含的问题添加了要求。当我按照您的描述运行 Get-Item 时,它会抛出说 bin 不存在,这在我的 git repo 的根目录中不存在。再次感谢您教导我们。
【解决方案2】:

对于任何人来说,就像我刚才一样,这里有一个完整的解决方案。 使用Lee_Dailey 建议的Where-Object,您可以在递归后排除node_modules 目录。

gci -include bin,obj -recurse | where-object {$_.FullName -notlike '*\node_modules*'} | remove-item -force -recurse

【讨论】:

    猜你喜欢
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 2018-09-20
    • 2017-01-05
    • 2019-01-18
    相关资源
    最近更新 更多