从函数

时间:2015-11-30 12:02:59

标签: arrays powershell powershell-v2.0

我正在试图弄清楚如何简化这个过程,但它并不像我想象的那么简单。

我有一个与此类似的配置文件:

[string][1][options]
$List = @(
   "c:\path\to\file,1,-a,-b,-c,-d,-e"
)

唯一需要的项目是[string][1]。有10个选项(-a-b等),可能更多。 每个都是可选的,可以按任何顺序提供。

在主脚本中,我现在执行以下操作:

foreach ($a in $List) {
    $dataSplit = $a -split"(,)"
    $string = $dataSplit[0]
    $number = $dataSplit[2]
    $ds4 = $dataSplit[4]
    if(!$ds4) { 
        $ds4 = "0" 
    } elseif($ds4.StartsWith("-a")) {
        $a_set = 1
        write-host "a_set has been set to $a_set"
    } elseif($ds4.StartsWith("-b")) {
        $b_set = 1
        write-host "b_set has been set to $b_set"
    }
    . . .
    if(!$ds5) { 
        $ds5 = "0" 
    }
    . . .

你可以想象这会变得很长。所以我想我会用一个函数来简化它。 e.g。

function get-additional($item) {
    if($item.StartsWith("-a")) {
        $a_set = 1
        Write-Host "$a_set has been set"
        return $a_set
    }
    if($item.StartsWith("-b")) {
        $b_set = 1
        Write-Host "$b_set has been set"
        return $b_set
    }
}

然后这样称呼它:

if(!$ds4) { 
    $ds4 = "0"
} else {
    get-additional($ds4)
}

有办法做到这一点吗?我已经看到了很多例子,如果你只有一个变量可以返回,或者甚至是一个固定的数字,但没有一个允许返回“众多”变量之一。

如果它有帮助,这里是(缩短的)脚本:

$List = @(
"c:\path\to\file,1,-b,-c,-d,-e"
)

function get-additional($item) {
    if($item.StartsWith("-a")) {
        $a_set = 1
        Write-Host "a_set has been set to $a_set"
        return $a_set
    }
    if($item.StartsWith("-b")) {
        $b_set = 1
        Write-Host "b_set has been set to $b_set"
        return $b_set
    }
}

$a_set = 0
$b_set = 0
$c_set = 0

foreach ($a in $List) {
    $dataSplit = $a -split"(,)"
    $string = $dataSplit[0]
    $number = $dataSplit[2]
    $ds4 = $dataSplit[4]
    Write-Host "ds4 = $ds4"
    if(!$ds4) {
        $ds4 = "0"
    } else {
        get-additional($ds4)
    }
    $ds5 = $dataSplit[6]
    Write-Host "ds5 = $ds5"
    if(!$ds5) {
        $ds5 = "0"
    } else {
        get-additional($ds5)
    }
}

Write-Host "a = $a_set"
Write-Host "b = $b_set"       

最后的期望结果是

a = 0
b = 1

- - - 更新2015-11-30 16:54

如果它有助于理解我的目标,那么我的实际脚本中的样本

$cfg_AppList = @(
"C:\Path\to\application1\app1.exe instance1,1"
"C:\Path\to\application2\app2.exe instance2,1,-p12345"
"C:\Path\to\application3\app3.exe instance3,0"
"C:\Path\to\application3\app3.exe instance3,1,-p78901"
)

function get-additional($item)
{
    $script:pval = "0"

    if($item.StartsWith("-p"))
        {
            $script:pval = $ds4.substring(2)
            write-host "$pval is a pval" 
        }
}

$AppObject = @()
foreach($a in $cfg_AppList)
    {
        $dataSplit = $a -split","
        $AppVal = $dataSplit[0]
        $checkVal = $dataSplit[1]
        $ds4 = $dataSplit[2]

        if(!$ds4) 
            { 
                $ds4 = "0" 
            }
        else
            {
                get-additional($ds4)
            }

        $AppObject += New-Object PSObject -property @{
            AppVal = "$AppVal";
            checkVal = "$checkVal";
            pval = "$pval";
            }
    }   

随着脚本的进行,$AppObject对象被引用和更新。 pval中提供的值和(见下文eval)将确定会发生什么。

我现在需要添加第二个元素-e,这将包括在内:

 $cfg_AppList = @(
"C:\Path\to\application1\app1.exe instance1,1"
"C:\Path\to\application2\app2.exe instance2,1,-p12345"
"C:\Path\to\application3\app3.exe instance3,0,-e"
"C:\Path\to\application3\app3.exe instance3,1,-e,-p78901"
)

将选择1或未选择0,并将$AppObject数组添加为eval=$eval(1 | 0)。

展望未来我有更多选择,我计划引入,因此需要找到最有效的方法来处理它们。

- - - 更新2015-12-01 11:39

好的,我所带的是以下两种想法的结合。 将选项放入数组并循环遍历它们,然后使用SWITCH语句查看设置了哪些。

$AppObject = @()
foreach($a in $cfg_AppList)
    {
        $pval = 0
        $eval = 0

        $AppVal,$CheckVal,$options = $a -split","

        foreach($opt in $options)
            {
                switch -wildcard ($opt) 
                    {
                       '-p*' { $pval = $opt.substring(2) }
                       '-e'  { $eval = 1 }
                    }
            }      

        $AppObject += New-Object PSObject -property @{
            AppVal = "$AppVal";
            CheckVal = "$CheckVal";
            pval = "$pval";
            eval = "$eval";
            }            
    }

2 个答案:

答案 0 :(得分:1)

首先,如果您不打算将其用于任何事情,请不要在分割操作中捕获,,只需使用-split ","(无括号)。

我们可以使用多个变量赋值来“移位”到字符串和数字1:

$s,$n,$opts = "string,1,-a,-b,-c" -split ","

$opts现在将包含字符串数组:@("-a","-b","-c")

检查是否存在预定选项集的最简单方法是简单地遍历所有可能的选项并查看它们是否包含在输入字符串中:

function Parse-InputString 
{
    param($InputString)

    # prepare the options you want to check for
    $PossibleOptions = "abcde".ToCharArray()

    # Split the input string 
    $String,$Number,$Options = $InputString -split ","

    # Create a new object with the string and number values
    $OutputObject = New-Object psobject -Property @{
        "String" = $String
        "Number" = $Number
    }

    # Now inspect the $Options array to see if any of them are set
    foreach($PossibleOption in $PossibleOptions){

        $OptionSet = if($Options -contains "-$PossibleOption"){
            1
        } else {
            0
        }

        # Add the information to the object
        $OutputObject |Add-Member -MemberType NoteProperty -Name $PossibleOption -Value $OptionSet
    }

    # return the object carrying all the information
    return $OutputObject
}

现在,您可以将输入字符串很好地解析为实际对象:

PS C:\> Parse-InputString -InputString "c:\path\to\file,1,-b,-c,-d,-e"

Number : 1
String : c:\path\to\file
a      : 0
b      : 1
c      : 1
d      : 1
e      : 1

答案 1 :(得分:0)

最简单的方法是更新函数中的全局变量而不返回任何内容:

function Get-Additional($item) {
    if ($item.StartsWith("-a")) {
        $global:a_set = 1
        Write-Host "a_set has been set to $a_set"
    }
    if ($item.StartsWith("-b")) {
        $global:b_set = 1
        Write-Host "b_set has been set to $b_set"
    }
}

但是,修改函数中的全局变量并不是一种好的做法,因为它很难调试。我不建议走这条路。

更好的方法是将当前值作为参数传递给函数,返回修改后的值,并将它们分配回变量。

function Get-Additional($item, $a, $b) {
    if ($item.StartsWith("-a")) {
        $a = 1
        Write-Host "a_set has been set to $a_set"
    }
    if ($item.StartsWith("-b")) {
        $b = 1
        Write-Host "b_set has been set to $b_set"
    }

    @($a, $b)
}

$set_a, $set_b = Get-Additional $ds4 $set_a $set_b

在上面的示例中,函数返回修改后的值(@($a, $b))列表,然后将其分配回列表$set_a, $set_b。从PowerShell函数返回内容时不需要return关键字。它仅控制从函数返回的位置,而不是返回的内容。

话虽如此,对于您的场景,我不会首先使用某个功能。 switch语句更适合这种操作:

switch -wildcard ($ds4) {
  '-a*' { $set_a = 1 }
  '-b*' { $set_b = 1 }
}