微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 Invoke-Expression 导航复杂/嵌套哈希表的更紧凑/优雅的方式?

如何解决使用 Invoke-Expression 导航复杂/嵌套哈希表的更紧凑/优雅的方式?

我正在开发一个通过键层次结构的字符串输入来访问/修改嵌套哈希表的函数,如下所示:
putH() $hashtable "key.key.key...等" “新价值”

给定:

$c = @{
       k1 = @{
              k1_1 = @{
                      k1_1_1 = @{ key = "QQQQQ"}
                      }
             }
      }

到目前为止,我已经想出了这个修改值的函数

function putH ($h,$hKEYs,$nVAL){
    if ($hKEYs.count -eq 1) {               
        $bID = $hKEYs                             #match the last remaining obj in $hkeys
    }
    else {
        $bID = $hKEYs[0]                          #match the first obj in $hekys
    }
    foreach ($tk in $h.keys){
        if ($tk -eq $bID){
            if ($hKEYs.count -eq 1){              #reached the last obj in $hkeys so modify
                $h.$tk = $nVAL
                break
            }  
            else {                                
                $trash,$hKEYs = $hKEYs                #take out the first obj in $hkeys
                $h.$tk = putH $h.$tk $hKEYs $nVAL     #call the function again for the nested hashtale
                break
            }
        }
    } 
return $h
}

还有这个获取值的函数

function getH ($h,$hKEYs){
if ($hKEYs.count -eq 1) {
    $bID = $hKEYs
}
else {
    $bID = $hKEYs[0]
}
foreach ($tk in $h.keys){
    if ($tk -eq $bID){
        if ($hKEYs.count -eq 1){
            $h = $h.$tk
            break
        }
        else {
        $trash,$hKEYs = $hKEYs
        $h = getH $h.$tk $hKEYs
        break
        }
    }
}
return $h
}

我像这样使用:

$s = "k1.k_1.k1_1_1"   #custom future input
$s = $s.split(".")
putH $c ($s) "NEW_QQQQQ" 
$getval = getH $c ($s)

我的问题:
有没有更优雅的方法来实现函数的结果……用 invoke-expression 说?
我试过 invoke-expression - 但无法通过它访问 hassstables(无论组合,嵌套引号如何)

$s = "k1.k_1.k1_1_1"   #custom future input
iex "$c.$s"
    

退货

System.Collections.Hashtable.k1.k_1.k1_1_1

解决方法

不要使用Invoke-Expression

我会在底部回答你的问题,但我觉得有必要指出调用 Invoke-Expression here is both dangerous,更重要的是,不必要

您可以通过简单地将“路径”分成其各个部分('A.B.C' -> @('A','B','C'))然后一一取消引用它们来解析整个嵌套成员引用链(您不需要甚至不需要为此递归!):

function Resolve-MemberChain 
{
  param(
    [Parameter(Mandatory = $true,ValueFromPipeline = $true)]
    [psobject[]]$InputObject,[Parameter(Mandatory = $true,Position = 0)]
    [string[]]$MemberPath,[Parameter(Mandatory = $false)]
    [ValidateNotNullOrEmpty()]
    [string]$Delimiter = '.'
  )

  begin {
    $MemberPath = $MemberPath.Split([string[]]@($Delimiter))
  }

  process {
    foreach($o in $InputObject){
      foreach($m in $MemberPath){
        $o = $o.$m
      }
      $o
    }
  }
}

现在您无需iex即可解决问题:

$ht = @{
  A = @{
    B = @{
      C = "Here's the value!"
    }
  }
}

$ht |Resolve-MemberChain 'A.B.C' -Delimiter '.'

您可以使用相同的方法来更新嵌套成员值 - 只需在最后一步停止,然后分配给 $parent.$lastMember

function Set-NestedMemberValue
{
  param(
    [Parameter(Mandatory = $true,position = 1)]
    $Value,[Parameter(Mandatory = $false)]
    [ValidateNotNullOrEmpty()]
    [string]$Delimiter = '.'
  )

  begin {
    $MemberPath = $MemberPath.Split([string[]]@($Delimiter))
    $leaf = $MemberPath |Select -Last 1
    $MemberPath = $MemberPath |select -SkipLast 1
  }

  process {
    foreach($o in $InputObject){
      foreach($m in $MemberPath){
        $o = $o.$m
      }
      $o.$leaf = $Value
    }
  }
}

在行动中:

PS ~> $ht.A.B.C
Here's the value!
PS ~> $ht |Set-NestedMemberValue 'A.B.C' 'New Value!'
PS ~> $ht.A.B.C
New Value!

为什么您目前的方法不起作用?

您当前实现面临的问题是,一旦评估字符串文字 $c$c.$s 中的 "$c.$s" 就会被扩展 - 为避免这种情况,只需转义第一个$

iex "`$c.$s"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。