2011-07-20 65 views
1

我在作爲Mercurial存儲庫的根目錄中運行以下命令。我想刪除任何文件,並以「.hg」開頭的文件夾:PowerShell刪除項目成功但拋出異常

gci -rec -filter ".hg*" | remove-item -recurse -force 

奇怪的是,它實際工作,但仍然會產生以下異常:

Get-ChildItem : Could not find a part of the path 'C:\temp\WSCopyTest\MyCompany.Services.DaftPunk\.hg\'. 
At line:1 char:4 
+ gci <<<< -rec -filter ".hg*" | remove-item -recurse -force 
    + CategoryInfo   : ReadError: (C:\temp\WSCopyT...es.DaftPunk\.hg:String) [Get-ChildItem], DirectoryNotFoundException 
    + FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand 

因爲異常拋出Get-ChildItem,我懷疑我對PowerShell中流水線的理解是有缺陷的。幾乎就像Get-ChildItem找到一個項目,將它傳遞給管道中的下一個cmdlet,然後查找下一個cmdlet?它是如何工作的?

下應該是一個腳本,將複製的問題,但是,在同一臺機器上,它完美的作品:

$repoRoot = "C:\Temp\HgDeleteTest\MyRepo" 
remove-item $repoRoot -recurse -force 
md $repoRoot 
pushd $repoRoot 
hg.exe init 
add-content ShouldBeLeftBehind.txt "This is some text in a file that should be left behind once the various .hg files/directories are removed." 
add-content .hgignore syntax:glob 
add-content .hgignore *.dll 
add-content .hgignore *.exe 
hg.exe commit --addremove --message "Building test repository with one commit." 
gci -rec -filter ".hg*" | remove-item -recurse -force 
popd 
+0

這裏同樣的問題,它在一臺機器上工作,但我得到另一個這個錯誤。 – johntrepreneur

+0

我懷疑它可能是一個PowerShell版本問題,如果有兩組行爲。 – johntrepreneur

回答

1

我結束了分離去除搜索。我相信我的問題是默認情況下(即一次一個項目)管道的工作方式,但我無法構建測試來檢查它。

在任何情況下,以下工作正常:

$hgObjects = gci -rec | ?{ $_.name -like ".hg*" -and $_.name -ne ".hgignore" } 
remove-item $hgObjects -force -recurse 

使用這種風格,remove-item cmdlet獲取發現項目的數組,並通過他們的作品。

我的原始示例中的.hg文件夾中沒有任何內容,稱爲.hg*,所以我沒有看到發生了什麼。感覺更像是試圖刪除文件夾兩次,這讓我覺得很奇怪。我不知道它實際上是這個標準的.NET行爲PowerShell的表現:

一個枚舉仍然有效的,只要集合保持不變 。如果對集合進行了更改(例如添加,修改或刪除元素),則枚舉器可能失效並且下一次調用MoveNext或Reset時可能會拋出一個 InvalidOperationException。如果集合在 MoveNext和Current之間修改,則即使枚舉器已失效,Current也會返回它設置爲的元素 。 (摘自http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator(v=vs.71).aspx)。

+0

是的,我剛剛遇到同樣的問題,並使用相同的修復程序。我注意到,當我從remove-item中分離出get-childitem時,開始移除項目需要更長的時間。這表明get-childitem在第一個結果可用時將第一個結果輸出到下一個操作(本例中爲remove-item),並在完成後繼續。 –

1

難道你刪除開始.hg一個文件夾,該文件又包含以.hg開頭的文件,但該文件不再存在?

0

我預料安東尼是正確的 - 在gci上使用-recurse會枚舉符合「.hg *」的文件和目錄。該目錄將首先返回。然後remove-item首先刪除目錄,然後-force開關刪除其中的所有文件。然後它會嘗試刪除那些與「.hg *」匹配的目錄中的文件(那是在gci運行時出現的),但現在它們已經不存在了。這應該停止錯誤:

gci ".hg*" -recurse | select -expand fullname | sort length -desc | remove-item -force 

遞減長度順序排序的全名,確保所有在該目錄中匹配的文件被刪除之前沒有匹配的父目錄被刪除。

1

以下將限制其刪除僅限文件,並排除文件夾。

gci -rec -filter ".hg*" | Where {$_.psIsContainer -eq $false} | remove-item -recurse -force 

然後再次運行它,通過刪除文件夾:

gci -rec -filter ".hg*" | Where {$_.psIsContainer -eq $true} | remove-item -recurse -force 
+0

爲什麼不刪除文件夾?我不認爲Mercurial會在.hg文件夾外生成任何類似的文件。 – JasonMArcher