Return 函数中的众多变量之一

Return one of many variables from a function

我正在想办法简化这个过程,但它并不像我想的那么简单。

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

[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" 
    }
    . . .

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

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)
}

有办法吗?如果您只有一个 return 变量,甚至是一个固定数字,但 none 允许 return 个 'one of many' 变量,我已经看过很多示例。

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

$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,并作为 eval=$eval (1|0) 添加到 $AppObject 数组。

展望未来,我计划介绍更多选项,因此需要找到最有效的方法来处理所有这些选项。

- - - 更新 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";
            }            
    }

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

我们可以利用多变量赋值 "shift" 到字符串和数字 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

最简单的方法是在不 return 任何东西的情况下更新函数中的全局变量:

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"
    }
}

但是,在函数中修改全局变量并不是一个好习惯,因为它很难调试。我不建议走这条路。

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

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

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

的内容

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

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