1

设置

我有一个看起来像这样的文件夹结构:

C:\RootFolder
            \file1.txt
            \file2.txt
            \license.txt
            \Settings
                     \fileA.txt
                     \fileB.txt
                     \settings.txt
            \OtherFolders

目标

删除除 license.txt 和 settings.txt 之外的所有文件。

最后,我希望只保留以下内容:

  C:\RootFolder
                \license.txt
                \Settings
                         \settings.txt

远方的剧本

$exclude = @('license.txt', 'settings.txt')
Get-ChildItem C:\RootFolder -recurse -exclude $exclude | foreach ($_) {remove-item $_.fullname -recurse:$false}

问题

即使我专门指定了 -recurse:$false,它总是会为每个文件夹生成一条消息,指示“未指定递归”并说它将删除所有子项。

在此之后, license.txt 文件仍然存在,但 settings.txt 文件(在子目录中)不会。

4

2 回答 2

3

几乎我一发布,答案就来了——我只需要找到文件,而不是目录。

由于我使用的是 PowerShell 2.0,因此我无法使用 powershell 3 中新增的 -File 属性。相反,我必须检查每个对象以查看它是否是容器。

解决方案:

$exclude = @('license.txt', 'settings.txt')

Get-ChildItem C:\RootFolder -recurse -exclude $exclude | Where-Object {!($_.PSIsContainer)} | foreach ($_) {remove-item $_.fullname}

这完美地实现了我所需要的。

改进解决方案

感谢这里的几条评论/帖子,有一些更优雅的方式教会了我更多关于 powershell 的知识:

  • Remove-Item 可以从管道中获取命令。不需要 foreach。
  • Where-Object 可以缩写为“?”
  • Get-ChildItem 可以缩写为“gci”(别名)
  • 在 Foreach 之后我们不需要 ($_)。Foreach 会自动理解这一点。
  • 如果我们想将排除项放在一行上,我们可以通过数组右内联来实现

鉴于这些,适合单线的优雅解决方案是:

gci C:\RootFolder -Recurse -Exclude @('license.txt', 'settings.txt') | ? { ! $_.PSIsContainer } | Remove-Item -Force
于 2013-07-11T20:11:03.343 回答
1

你的代码很好用。

只是一条线,所以我们可以用另一种方式来做:

Get-ChildItem C:\RootFolder -recurse | Where-Object {!($_.PSIsContainer)} | Foreach { if ( $_.Name -ne "license.txt" -and $_.Name -ne "settings.txt") {remove-item $_.FullName -force}}

如果有很多文件需要被排除,那么这个衬里就不能扩展——在这种情况下,我将使用你的代码:)

@Sean Killeen 顺便说一句:在 foreach 之后有 ($_)吗?听起来您使用的是 Foreach-Object Cmdlet 而不是 Foreach 构造。我的理解是对于 Cmdlet 我们在“foreach-object”之后不需要 ($something in $sometingElse)。但是在 Foreach 构造中我们需要 ($something in $somethingElse)。如果我错了,请纠正我。

于 2013-07-11T23:48:37.390 回答