簡體   English   中英

PowerShell Remove-Item 不等待

[英]PowerShell Remove-Item not waiting

如果有這段代碼

if(Test-Path -Path $OUT) 
{ 
    Remove-Item $OUT -Recurse 
}
New-Item -ItemType directory -Path $OUT

有時它有效,但有時 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

那么它總是有效。 如何強制 Remove-Item 確保文件夾被真正刪除? 或者我想念別的東西?

更新從(至少[1] )Windows 10 版本20H2 (我不知道對應的 Windows Server版本和版本;運行winver.exe以檢查您的版本和版本), DeleteFile Windows API 函數現在顯示同步行為,它隱式地解決了 PowerShell 的Remove-Item和 .NET 的System.IO.File.Delete / System.IO.Directory.Delete (但奇怪的是,不是cmd.exerd /s )。


Remove-Item -Recurse出乎意料地是異步的,最終是因為用於文件和目錄刪除Windows API 方法本質上是異步的,Remove-Item沒有考慮到這一點。

間歇性地、不可預測地表現為以下兩種方式之一:

  • 您的情況:刪除后立即重新創建已刪除的目錄可能會失敗,因為在嘗試重新創建時刪除可能尚未完成。

  • 更典型的是:如果在嘗試刪除父目錄時子目錄或文件的刪除尚未完成,則刪除非空目錄本身可能會失敗 - 這在ServerFault 回答marsze 鏈接中進行了演示。

一個潛在的解決方法是通過清空現有目錄來重用它 - 而不是刪除並重新創建它。

但是,使用Get-ChildItem $OUT -Recurse | Remove-Item -Recurse清空目錄 Get-ChildItem $OUT -Recurse | Remove-Item -Recurse容易受到間歇性故障的影響,盡管可能不那么頻繁。

該問題不僅會影響 PowerShell 的Remove-Item ,還會影響cmd.exerd /s以及 .NET 的[System.IO.Directory]::Delete()

從 Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 / cmd.exe 10.0.17134.407 / .NET Framework 4.7.03056 開始,.NET Core 2.1,既不是Remove-Item ,也不是rd /s ,也不是[System.IO.Directory]::Delete()工作可靠,因為它們無法解釋 Windows API 文件/目錄刪除函數的異步行為

有關提供可靠同步解決方法自定義 PowerShell 函數,請參閱此答案


[1] 通過在GitHub 問題 #27958 中運行測試數小時而沒有失敗,我已經親自驗證了該問題在版本20H2得到解決; 這樣的回答表明,問題早解決版本1909 ,開始構建18363.657 ,但庭陳德良認為,解決問題作為構建18363.1316除去大的目錄樹時,如node_modules 我找不到有關該主題的任何官方信息。

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
}

筆記:

  • Get-ChildItem命令只查找非隱藏文件和子目錄,所以清空目標目錄可能不完整; 要也包括隱藏項目,請添加-Force

  • 同樣,將-Force添加到-RemoveItem以強制刪除設置了只讀屬性的文件。

    • 如果沒有-Force ,清空可能再次不完整,但在這種情況下你會得到非終止錯誤; 如果您想將它們視為終止錯誤,請添加-ErrorAction Stop

為了完整起見:您還可以使用安全且快速的 .NET 方法:

if ([System.IO.Directory]::Exists($OUT)) {
    [System.IO.Directory]::Delete($OUT, $true)
}
[System.IO.Directory]::CreateDirectory($OUT)

筆記:

根據您獲得$OUT值的位置,您可能希望首先將其轉換為完整路徑,以確保 .NET 方法刪除正確的目錄(請參閱 @mklement0 的評論):

$fullPath = Convert-Path $OUT

如果您鍵入Get-Help Remove-Item -Detailed您將看到:

 Example 4: Delete files in subfolders recursively PS C:\\>Get-ChildItem * -Include *.csv -Recurse | Remove-Item This command deletes all of the CSV files in the current folder and all subfolder recursively.

由於 Remove-Item 中的 Recurse 參數存在已知問題,因此本示例中的命令使用 Get-ChildItem 獲取所需文件,然后使用管道運算符將它們傳遞給 Remove-Item 。

執行規范建議的操作:

if(Test-Path -Path $OUT) 
{ 
    Get-ChildItem $OUT -Recurse | Remove-Item
}
New-Item -ItemType directory -Path $OUT

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM