如何使用PowerShell 2.0递归删除整个目录?

458
什么是在PowerShell中强制删除目录及其所有子目录的最简单方法?我正在使用Windows 7中的PowerShell V2。
我从多个来源了解到,最明显的命令Remove-Item $targetDir -Recurse -Force不能正确工作。这包括PowerShell V2在线帮助中的一条语句(使用Get-Help Remove-Item -Examples找到),该语句如下:
“...因为此 cmdlet 中的 Recurse 参数存在故障,所以该命令使用 Get-Childitem cmdlet 获取所需文件,并使用管道运算符将它们传递给 Remove-Item cmdlet …”
我看到各种示例使用Get-ChildItem并将其导入Remove-Item,但这些示例通常基于过滤器删除某些文件集,而不是整个目录。
我正在寻找最干净的方法来清空整个目录,包括文件和子目录,而不使用任何用户警告消息,尽量少的代码。如果可以理解,一行代码就足够了。

2
PowerShell,我知道,但是 RD /S /Q - Rubens Farias
2
在PowerShell中似乎无法使用"RD /S /Q"命令,会提示"Remove-Item : A positional parameter cannot be found that accepts argument '/q'." - BrainSlugs83
8
在PowerShell中,rdRemove-Item的别名。但使用cmd /c "rd /s /q"也是可行的。 - codekaizen
2
我简直无法相信PowerShell会通过隐藏完全可用的MS-DOS命令来破坏基本功能!在CMD中,您可以使用rmdir或rd,但它们在PowerShell中都被劫持了。 - JonnyRaa
1
还有这个:https://dev59.com/fFQJ5IYBdhLWcg3wkG2-#53561052 - Andrew Savinykh
显示剩余2条评论
22个回答

779
Remove-Item -Recurse -Force some_dir

确实像这里宣传的那样有效。

rm -r -fo some_dir

这些是同样有效的速记别名。

据我了解,当您尝试递归地删除筛选出的文件集时,-Recurse参数似乎无法正常工作。对于删除单个目录及其下面的所有内容,则似乎可以正常工作。


8
我认为你是正确的。我遇到了“无法删除'some directory'中的项目,因为它正在使用”的错误,并假设这是递归算法的问题,于是开始寻找解决方法。结果发现,之前在脚本中启动的一个进程正在目标目录中工作。当我修改了脚本以等待其他进程时,“Remove-Item -Recurse -Force”命令就可以使用了。总是先审视自己 :) - Matt Spradley
26
我发现当运行在包含子目录的目录上时,需要运行两次。第一次会出现许多“目录不是空的”错误。第二次则会顺利完成且没有错误。 - Kristopher Johnson
5
在Windows 7上,我使用不同的工具也会遇到类似的错误。似乎删除操作返回的时间比实际上删除文件或文件夹的时间早,有时会导致问题。这种情况似乎在资源管理器、Far、命令提示符和PowerShell中都会发生。 - Joey
2
@Joey “似乎删除调用比实际删除文件或文件夹更早返回,有时会引起麻烦。” --> 为了澄清:父文件夹不会被删除,而是会出现以下错误:“[父文件夹]无法删除,因为它不为空。” 我经常在(慢速)网络驱动器上看到这种情况发生。唯一的解决方案是旧方法:如下所述的 cmd /c rd - Davor Josipovic
7
关于“目录不为空”错误的问题?也许最好使用命令:get-childitem * -include *.csv -recurse | remove-item。我不确定,参考链接:http://stackoverflow.com/a/1668471/206730。 - Kiquenet
显示剩余10条评论

45

我使用了:

rm -r folderToDelete

这对我非常有效(我从Ubuntu那里偷了它)。


这不需要cygwin、git或其他能在Windows上模拟bash shell的工具吗? - Pete
21
@Pete,不,它只需要PowerShell。在PowerShell的默认配置中,rmRemove-Item的别名。查看Get-Alias rm命令的输出以获取更多详细信息。-r利用了PowerShell对参数部分匹配的行为。由于Remove-Item只有一个以'r'开头的参数-Recurse,因此-r与之匹配。因此,以下所有命令都可以达到相同的效果:rm -rrm -reRemove-Item -Recurse。(请注意,rm -rfrm -r -f都不起作用,但是rm -r -fo会起作用。-rf不匹配任何参数,-f匹配多个。) - chwarr
1
那怎么样呢?Powershell中的rm别名,用于“Remove-Item -Recurse -Force some_dir”比直接使用remove-item更好。我收到了相同的错误“无法删除'some directory'处的项目”。我从remove-item切换到rm -r,没有错误!? - Greg
有趣。我在我的电脑上安装了cygwin工具,并尝试过rm -rf folder,当然失败了。一开始我对答案进行了负评(因为它说的是Ubuntu)。多亏了@chwarr的评论,我尝试了不带f的命令,这样就可以使用别名而不是rm二进制文件了。我希望Tuan能够更新他的源代码(不确定Tuan是否知道这是一个别名,还是真的认为这是Unix的rm ;-))。 - Joshua Ball
2
也许是因为我使用了 -R 而不是 -r(尽管据我所知,PowerShell 像 Windows 的其他部分一样不区分大小写,因此不应该有任何区别),但我收到了一个错误,说我要删除的文件夹不为空。 - rbaleksandar
1
它在PowerShell 5.1上无法工作,我不得不使用rm -r -form -r -f也无法工作,因为-f参数是模糊的,它可以匹配-Force-Filter)。 - Géry Ogam

34

使用简单的Remove-Item "folder" -Recurse递归删除文件时,有时会出现间歇性错误:[folder]无法删除,因为它不为空。

本答案尝试通过分别删除文件来避免该错误。

function Get-Tree($Path,$Include='*') { 
    @(Get-Item $Path -Include $Include -Force) + 
        (Get-ChildItem $Path -Recurse -Include $Include -Force) | 
        sort pspath -Descending -unique
} 

function Remove-Tree($Path,$Include='*') { 
    Get-Tree $Path $Include | Remove-Item -force -recurse
} 

Remove-Tree some_dir

一个重要的细节是使用pspath -Descending对所有项目进行排序,以便在删除根之前删除叶子。 对pspath参数进行排序,因为它在比文件系统更常用的提供程序中有更大的工作机会。 如果您想要筛选要删除的项目,则-Include参数只是方便。

将其分成两个函数,因为我发现通过运行可以清楚地看到我即将删除的内容。

Get-Tree some_dir | select fullname

3
在使用 PowerShell 处理 TFS 构建脚本时,这被证明是正确的解决方法。 - rcabr
1
这对我也是解决方案。你做得很好,给你一些积分吧! - Jammer
对我很有用。我无法递归删除文件夹内容,但是您的解决方案对我起作用了。谢谢。 - sheldonhull
这是一个非常强大的解决方案。 - Max Young
1
我不确定为什么被接受的答案有这么多票 - 我个人在使用Powershell v5中仍然会偶尔出现错误,因此这个解决方案对我来说是最好的。 - JonoB
可能有一个更强大的解决方案:https://dev59.com/fFQJ5IYBdhLWcg3wkG2-#53561052 - David Faivre

17
rm -r ./folder -Force    

...对我很有用


14

试试这个例子。如果目录不存在,不会引发错误。您可能需要 PowerShell v3.0。

remove-item -path "c:\Test Temp\Test Folder" -Force -Recurse -ErrorAction SilentlyContinue

14

如果你执着于PowerShell,你可以使用此方法,如所接受的答案所解释:

rm -r -fo targetDir

但我发现使用Windows命令提示符更快

rmdir /s/q targetDir

使用命令提示符选项的另一个优点是它开始立即删除文件(PowerShell 需要先进行一些枚举),因此如果在运行过程中出现故障,您至少已经在删除文件方面取得了一些进展。


1
rmdir 除了常规删除目录的功能外,还能成功删除只读文件(如.git文件夹)-- 在较老的Powershell版本中,(get-item targetDir).Delete($true)将无法删除Git仓库。 - Carl Walsh

10

使用老派的DOS命令:

rd /s <dir>

2
如果这是脚本的一部分,你需要使用 /q(安静模式,不要询问是否删除带有 /S 的目录树) - wildeyes

10
为了避免接受答案中的“目录不为空”错误,只需像之前建议的那样使用好老的DOS命令即可。完整的PS语法已准备好复制粘贴:
& cmd.exe /c rd /S /Q $folderToDelete

4
文件夹仍然会显示“目录不为空”的错误提示吗? - Oncel Umut TURER
我想删除一个Android Studio项目,然后在关闭Android Studio之后,这个操作成功了! - Mohamad Ghaith Alzin

9

由于某些原因,John Rees的答案在我的情况下有时候不起作用。但是它引导我朝以下方向前进。 首先,我尝试使用有问题的-recurse选项递归地删除目录。然后,我进入剩下的每个子目录并删除所有文件。

function Remove-Tree($Path)
{ 
    Remove-Item $Path -force -Recurse -ErrorAction silentlycontinue

    if (Test-Path "$Path\" -ErrorAction silentlycontinue)
    {
        $folders = Get-ChildItem -Path $Path –Directory -Force
        ForEach ($folder in $folders)
        {
            Remove-Tree $folder.FullName
        }

        $files = Get-ChildItem -Path $Path -File -Force

        ForEach ($file in $files)
        {
            Remove-Item $file.FullName -force
        }

        if (Test-Path "$Path\" -ErrorAction silentlycontinue)
        {
            Remove-Item $Path -force
        }
    }
}

你能在运行我的函数时重现这个错误吗?我想知道这样我才能改进它们。 - John Rees
抱歉,我不记得确切的设置了 :/ 我想是在涉及多个子目录时发生的。 情况是调用“Remove-Item -force -recurse”未删除所有文件,在这种情况下,最后一个Remove-Tree失败,因为目录不为空。这就是为什么我想出了新的解决方案,首先尝试有缺陷的内置版本(-force),然后手动进入每个目录并“手动”删除剩余的内容。这个版本经常使用,到目前为止它一直在工作。唯一导致它失败的原因是某个程序仍然持有对目录的句柄。 - jdoose

4
删除整个文件夹树有时会成功,有时会出现“目录不为空”的错误。随后尝试检查文件夹是否仍然存在可能会导致“访问被拒绝”或“未经授权的访问”错误。我不知道为什么会发生这种情况,但这篇StackOverflow文章可能会提供一些见解。
我已经通过指定文件夹内项目的删除顺序并添加延迟来解决这些问题。以下内容对我而言运行良好:
# First remove any files in the folder tree
Get-ChildItem -LiteralPath $FolderToDelete -Recurse -Force | Where-Object { -not ($_.psiscontainer) } | Remove-Item –Force

# Then remove any sub-folders (deepest ones first).    The -Recurse switch may be needed despite the deepest items being deleted first.
ForEach ($Subfolder in Get-ChildItem -LiteralPath $FolderToDelete -Recurse -Force | Select-Object FullName, @{Name="Depth";Expression={($_.FullName -split "\\").Count}} | Sort-Object -Property @{Expression="Depth";Descending=$true}) { Remove-Item -LiteralPath $Subfolder.FullName -Recurse -Force }

# Then remove the folder itself.  The -Recurse switch is sometimes needed despite the previous statements.
Remove-Item -LiteralPath $FolderToDelete -Recurse -Force

# Finally, give Windows some time to finish deleting the folder (try not to hurl)
Start-Sleep -Seconds 4

一篇微软TechNet文章使用计算属性在PowerShell中帮助我按深度获取子文件夹列表。

RD /S /Q的类似可靠性问题可以通过在运行RD /S /Q之前运行DEL /F /S /Q并在必要时第二次运行RD来解决 - 最好在两次之间暂停(即使用如下所示的ping)。

DEL /F /S /Q "C:\Some\Folder\to\Delete\*.*" > nul
RD /S /Q "C:\Some\Folder\to\Delete" > nul
if exist "C:\Some\Folder\to\Delete"  ping -4 -n 4 127.0.0.1 > nul
if exist "C:\Some\Folder\to\Delete"  RD /S /Q "C:\Some\Folder\to\Delete" > nul

请参考David Faivre在下面的回答中提到的这个答案,了解为什么有时候删除目录会失败,以及更高级的解决方法。 - MikeOnline

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