【问题标题】:Powershell exiting loop causes infinite recursionPowershell退出循环导致无限递归
【发布时间】:2015-11-30 21:09:39
【问题描述】:

由于某种原因,下面的 powershell 代码进入了一个无限循环,我不知道为什么。

最低try 块中的代码无法成功,所以我希望catch 捕获错误,然后循环继续。

但它会无限循环,创建越来越多的子目录。

这是为什么呢?

在 powershell v5.0 上测试

在包含至少一个子文件夹的文件夹中尝试代码,该文件夹本身至少包含一个文件。你会明白我的意思。

Get-ChildItem -Recurse | Where-Object { $_.PSIsContainer} | ForEach-Object {

    $path = $_
    set-Location $path

    #get all items, exclude zip files and folders
    $items = Get-ChildItem -Exclude *.zip | Where-Object { -not $_.psIsContainer}

    #verify that there are items in this directory, catch errors
    if ( $items ) {
        $newfld = New-Item -ItemType Directory -name "blabla"

        #move items to newly-created folder
        Move-Item $items -destination $newfld.Fullname 

        #try to do something that is destined to fail   
        try{
            [void][System.Reflection.Assembly]::LoadFrom($ZipModule)
        }
        catch { 
            Write-Host "No Zip"
        }
    }
}

【问题讨论】:

  • try{}catch{}if 语句中是怎么回事?字符串"No items" 将被解释为$true,完全违背了Test-Path 的目的
  • 什么意思?语句中的第一个try{}catch{} 是检查文件夹是否包含项目,即$items 不为空。
  • 您不需要Test-Path,只需检查$items 是否包含任何内容:if($items){ # do stuff }
  • @MathiasR.Jessen - 这是非常有用的反馈,谢谢!不过,它根本没有回答我的问题。测试代码,你就会明白我的意思了。

标签: powershell for-loop recursion zip infinite-loop


【解决方案1】:

您检查$items 是否包含任何文件的方法太复杂了,并且行为会与您的预期不同。

您可以检查是否返回了任何文件:

if($items){
    # move/zip/create etc.
}

如果Get-ChildItem返回0个文件,$items将被解释为$false,否则$true


关于无限循环行为,Get-ChildItem -Recurse 似乎一直在后台异步运行并拾取您在此期间创建的blabla 文件夹。

您可以强制 Get-ChildItem -Recurse 在管道到 ForEach-Object 之前返回,方法是将调用包含在 () 中:

(Get-ChildItem -Recurse | Where-Object { $_.PSIsContainer}) | ForEach-Object {
    # create/move/zip etc.
}

或者,在循环之前的单独语句中将所有目录(您实际上只需要FullName 属性)分配给一个变量:

$Directories = Get-ChildItem -Recurse |Where-Object { $_.PsIsContainer } |Select-Object FullName
foreach($Path in $Directories){
    # create/move/zip etc.
}

【讨论】:

  • 好的,非常感谢。我已经进行了更改,但代码仍在无限循环中。在包含至少一个其他文件夹的文件夹中尝试它,该文件夹本身至少包含一个文件。你会明白我的意思。
  • 没注意到外面的Get-ChildItem -Recurse电话,让我看看能不能重现。
  • 啊,好吧,很公平。是的,该代码旨在压缩所有子文件夹的内容。但是,我注意到如果压缩失败,那么循环会重新启动并无限循环。顺便说一句,非常感谢您的帮助。
  • @Charon 是的,也可以在 PowerShell 4.0 中重现(和缓解)。查看更新
  • 我明白了.....谢谢!这很有趣,你的回答很有效,所以我接受了。您有相关信息的链接吗?
【解决方案2】:

它进入无限循环的原因是因为你要进入一个子文件夹,检查它是否有文件(非 ZIP 文件),如果有,创建一个名为“blabla”的新文件夹并移动文件进入那个文件夹。所以代码正在做的是将文件夹中的文件移动到该文件夹​​的子文件夹中,依此类推。如果您想将文件移动到子文件夹中,然后将其压缩并删除文件,那将停止无限递归。

每次创建子文件夹“blabla”时,都会使递归永久化。

【讨论】:

  • 我当然明白这一点。但问题是,为什么它会这样?我要求它获取子文件夹一次,一开始,我不明白为什么它一直这样做。
  • @Charon 因为Get-ChildItem 不需要在管道继续之前返回。这是一种带有一些奇怪副作用的语言功能 :)
猜你喜欢
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-06
  • 2017-07-27
  • 1970-01-01
  • 2016-11-07
相关资源
最近更新 更多