PowerShell Remove-Item不等待

arm*_*enm 5 filesystems powershell ntfs synchronous

如果有这段代码

if(Test-Path -Path $OUT) 
{ 
    Remove-Item $OUT -Recurse 
}
New-Item -ItemType directory -Path $OUT
Run Code Online (Sandbox Code Playgroud)

有时它可以工作,但有时New-Item行会产生PermissionDenied ItemExistsUnauthorizedAccessError错误。我认为这意味着以前的Remove-Item尚未完全执行,并且无法创建文件夹,因为该文件夹仍然存在。

如果我在那里睡觉

if(Test-Path -Path $OUT) 
{ 
    Remove-Item $OUT -Recurse 
    Start-Sleep -s 1
}
New-Item -ItemType directory -Path $OUT
Run Code Online (Sandbox Code Playgroud)

然后它总是可以工作。如何强制Remove-Item以确保文件夹已真正删除?还是我想念其他东西?

mkl*_*nt0 7

更新:似乎有计划使Windows文件系统项删除API同步,但是从Windows 10版本1903开始它们尚未同步-请参阅GitHub上的注释


Remove-Item -Recurse意外地是异步的,最终是因为用于删除文件和目录Windows API方法本质上是异步的Remove-Item不能解决这个问题。

这以两种方式之一间歇地,不可预测地体现出来:

  • 您的情况:删除后立即重新创建删除的目录可能会失败,因为在尝试重新创建时删除可能尚未完成。

  • 更典型的是:如果在尝试删除父目录时尚未完成子目录或文件的删除,则删除非空目录本身可能会失败-这在ServerFault答案 marsze链接中得到了证明。

marsze的有用答案提供了一种解决方法:无需重新创建目录,只需清空并重用它,就可以绕开问题。

然而,排空与目录Get-ChildItem $OUT -Recurse | Remove-Item -Recurse容易受到间歇性故障,虽然可能较少。

这个问题不仅影响PowerShell的Remove-Item,但还cmd.exerd /s,以及.NET的[System.IO.Directory]::Delete()

由于的Windows PowerShell V5.1的/ PowerShell核心6.2.0-preview.1 / cmd.exe10.0.17134.407 / .NET框架4.7.03056,.NET 2.1的核心,既没有Remove-Item,也没有rd /s,也没有[System.IO.Directory]::Delete()可靠地工作,因为他们没有考虑到异步Windows API文件/目录删除功能的行为

有关提供可靠同步解决方案自定义PowerShell功能,请参见以下答案


mar*_*sze 6

Remove-Item命令有一个已知问题

试试这个:

if (Test-Path $OUT) 
{ 
    # if exists: empty contents and reuse the directory itself
    Get-ChildItem $OUT -Recurse | Remove-Item -Recurse
}
else
{
    # else: create
    New-Item -ItemType Directory -Path $OUT
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • Get-ChildItem命令只查找非隐藏文件和子目录,所以清空目标目录可能不完整;要也包含隐藏项目,请添加-Force.

  • 同样,添加-Force-RemoveItem强制删除具有只读属性集的文件。

    • 如果没有-Force,清空可能再次不完整,但在这种情况下你会得到非终止错误;如果您想将它们视为终止错误,请添加-ErrorAction Stop