【问题标题】:PowerShell remove-item succeeds but throws exceptionPowerShell 删除项目成功但抛出异常
【发布时间】:2011-07-20 20:33:55
【问题描述】:

我在 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

【问题讨论】:

  • 同样的问题在一台机器上工作,但我在另一台机器上得到这个错误。
  • 我怀疑如果有 2 组行为可能是 powershell 版本问题。

标签: powershell mercurial


【解决方案1】:

可能是您要删除一个以 .hg 开头的文件夹,而该文件夹又包含一个以 .hg 开头的文件,但该文件不再存在?

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      以下将其删除限制为仅文件,并排除文件夹。

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

      然后通过删除文件夹再次运行它:

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

      【讨论】:

      • 为什么不只删除文件夹?我认为 Mercurial 不会在 .hg 文件夹之外生成任何类似的文件。
      【解决方案4】:

      我最终将搜索与删除分开。我相信我的问题与默认情况下管道的工作方式(即一次一个项目)有关,但我无法构建测试来检查它。

      无论如何,以下工作正常:

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

      使用这种样式,remove-item cmdlet 会获取找到的项目数组并对其进行处理。

      我原始示例中的.hg 文件夹中没有任何名为.hg* 的内容,所以我看不出发生了什么。感觉更像是试图两次删除文件夹,我觉得这很奇怪。我想知道它是否实际上是这种标准 .NET 行为的 PowerShell 表现形式:

      只要集合仍然存在,枚举器就保持有效 不变。如果对集合进行了更改,例如添加, 修改或删除元素,可以使枚举器失效并 对 MoveNext 或 Reset 的下一次调用可能会引发 无效操作异常。如果集合在之间被修改 MoveNext 和 Current, Current 返回它设置为的元素, 即使枚举器已经失效。 (取自http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator(v=vs.71).aspx)。

      【讨论】:

      • 是的,我刚刚遇到了同样的问题并使用了相同的修复方法。我注意到,当我从 remove-item 中拆分 get-childitem 时,开始删除项目需要更长的时间。这表明 get-childitem 将第一个结果通过管道传递给下一个操作(在本例中为 remove-item),并在完成后继续。
      猜你喜欢
      • 1970-01-01
      • 2016-05-04
      • 2018-04-27
      • 2015-01-24
      • 2019-05-26
      • 2015-08-15
      • 2017-09-01
      • 2014-08-25
      • 2014-05-20
      相关资源
      最近更新 更多