PowerShell remove-item成功但抛出异常

时间:2011-07-20 10:06:58

标签: powershell mercurial

我在Mercurial存储库的根目录中运行以下命令。我想删除以“.hg”开头的所有文件和文件夹:

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,然后查找下一个?那是怎么回事?

以下应该是一个可以复制问题的脚本,但是,在同一台机器上,它可以完美地运行:

$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

4 个答案:

答案 0 :(得分:1)

你是否正在删除以.hg开头的文件夹,而该文件夹又包含一个以.hg开头的文件,但该文件已不存在?

答案 1 :(得分: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

答案 2 :(得分: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)。

答案 3 :(得分:0)

我希望Antony是正确的 - 使用gci上的-recurse会枚举匹配“.hg *”的文件和目录。该目录将首先返回。然后remove-item首先删除目录,-force开关删除其中的所有文件。然后它尝试删除该目录中与“.hg *”匹配的文件(当gci运行时存在),但它们现在已经消失了。这应该可以阻止错误:

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

按照长度的降序对全名进行排序可确保在删除该目录中所有匹配的文件之前不删除任何匹配的父目录。