[英]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.exe
的rd /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.exe
的rd /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.