功能变量的范围

时间:2017-04-17 12:53:02

标签: powershell

我需要递归计算mp3flac个文件的数量。这是我的代码:

function GetStat() 
{
    $mp3_count = 0 
    $flac_count = 0
    Set-Variable -Name mp3_count,flac_count -Option AllScope

    function getFiles($path) 
    {     
        foreach ($item in Get-ChildItem $path)
        {
            if (Test-Path $item.FullName -PathType Container) 
            {

                GetFiles $item.FullName
            } 
            else 
            { 
                if ($item.Extension -eq ".mp3")
                {                    
                    $mp3_count = $mp3_count + 1                 
                }

                if ($item.Extension -eq ".flac")
                {
                    $flac_count = $flac_count + 1                   
                }
            }
        } 
    }

    getFiles "Y:\music (flac)\Alternative"
    $mp3_count
    $flac_count
}

我的函数写0, 0,每次调用函数$mp3_count时都会重置flac_countgetFiles()个变量。

如何修复代码?

4 个答案:

答案 0 :(得分:2)

您只需使用A a = new A(); a.m1(); B b = new B(); b.m2(); 即可跳过所有这些操作。但是如果你想自己实现递归,这里有几个指针。

我建议不要写入本地范围之外的变量!

使您的递归函数返回一个哈希表,然后将每个递归的值添加到本地哈希表:

Get-ChildItem -Recurse

现在您可以使用以下方法检索每种类型的计数:

function Get-FileCount 
{
    param(
        [Parameter(Mandatory=$false)]
        [ValidateScript({Test-Path -LiteralPath $_ -PathType Container})]
        [string]$Path = (Resolve-Path $PWD),

        [Parameter(Mandatory=$false)]
        [string[]]$Extensions = @('flac','mp3')
    )

    # build local table to hold counts per extension
    $ExtensionCount = @{}

    # add dot to extensions if missing
    $Extensions = $Extensions |ForEach-Object {
        $_ -replace '^(?=[^\.])','.'
    }

    # retrieve all items at current $Path
    Get-ChildItem -LiteralPath $Path |ForEach-Object {
        # recurse if directory
        if($_ -is [System.IO.DirectoryInfo]){
            # retrieve count from subfolder
            $Subcount = Get-FileCount -Path $_.FullName -Extensions $Extensions
            foreach($Extension in $Subcount.Keys){
                # add results from recursive call for each identified extension to current count
                $ExtensionCount[$Extension] += $Subcount[$Extension]
            }
        } 
        elseif($_.Extension -in $Extensions) {
            # increment count for the found extension in local $Path
            $ExtensionCount[$_.Extension]++
        }
    }

    # return the counting table
    return $ExtensionCount
}

如果你想添加新的文件类型,你不需要重写任何东西:

Get-FileCount "Y:\music (flac)\Alternative"

答案 1 :(得分:0)

一般来说,除非你绝对需要,否则不要触及全球范围。你的函数中有很多额外的东西,包括一个不必要的嵌套函数。这是做同样事情的更实用的方法:

# Functions should be named Verb-<Whatever>
function Get-MediaStats ($Path) 
{
    # Everything that was here was extra and unneeded.
    foreach ($item in Get-ChildItem $path -Recurse)
    {
        if ($item.Extension -eq ".mp3")
        {                    
            $mp3_count++                 
        }

        if ($item.Extension -eq ".flac")
        {
            $flac_count++               
        }
    } 

    # This creates an object... The 'return' or 'write-output' is implied.
    [PSCustomObject]@{
        'MP3Count' = $mp3_count
        'FLACCount' = $flac_count
    }

}

# Instead of nested functions you can call the function like so... 
# Because it's returning a an object the variable $Result will contain the output.
$Results = Get-MediaStats C:\Path\To\Files
$Results

另请注意,您可以使用$Var++而不是$Var = $Var + 1

来增加变量

使用对象而不是全局变量在函数之间或函数之外传递东西是正确的方法:

Function Return-Something {
    Write-Output 'Something'
}

Function Return-Something {
    return 'Something'
}

Function Return-Something {
    'Something'
}

Function Return-Something {
    [PSCustomObject]@{
        'Something' = 'Something'
    }
}

如果您$Result = Return-Something

,那么其中任何一个都会有用

答案 2 :(得分:0)

我会以$items=Get-ChildItem -Recurse -File -Filter "*.mp3" -Path $pathToQuery递归获取所有文件。然后是用户$items.Count。您可以针对具有多个扩展程序的一次扫描进行优化,然后在使用Where-Object进行自定义推理的计数过滤器之前进行优化。例如

$items=Get-ChildItem -Recurse -File -Filter @("*.mp3","*.flac") -Path $pathToQuery
($items|Where-Object {#filter1 reasoning}).Count
($items|Where-Object {#filter2 reasoning}).Count

答案 3 :(得分:0)

Mathias R. Jessen已经提供了一个很好的答案,但是对于简单的事情,您可以将Get-ChildItem-Recurse参数一起使用,并将其传递给Group-Object以使其更加简单。

Function Get-FileCount{
Param(
    [string]$Path,
    [string[]]$Extensions = ".MP3",".FLAC"
)
    # Sanitize extensions
    $Extensions = $Extensions -replace "^(?:.*\.)?([^\.]+)$",'.$1'
    #Locate, filter, and group files
    Get-ChildItem $Path -Recurse | Where{ $_.Extension -in $extensions } | Group Extension | Select Name,Count
}

然后你可以这样称呼它:

Get-FileCount "Y:\music (flac)\Alternative"

它会输出如下内容:

Name    Count
----    -----
.mp3    37
.flac   163