【问题标题】:How do I select certain hashtable values but change others in-line in a powershell script如何选择某些哈希表值但在 powershell 脚本中内联更改其他值
【发布时间】:2016-06-16 23:53:53
【问题描述】:

使用管道或其他类型的内联表示法,我想直接“选择”哈希表中的某些值以获得结果,同时更改或设置其他值。

哈希表

我从一个哈希表开始(坦率地说,它就像一个对象一样使用),如下所示:

>$hash

Name               Value
----               -----
System             server-1
Job                Microsoft.PowerShell.Commands.PSWmiJob
Result

有没有办法使用 Select-Object cmdlet(或类似的东西)来设置某些属性的值并传递其他属性?我想结束这个:

>$hash

Name               Value
----               -----
System             server-1
Job                Microsoft.PowerShell.Commands.PSWmiJob
Result             Good

如果我不需要/不希望它是内联的,我只需设置 Result 的值:

$hash.Result = "good"

对于内联解决方案,我总是可以像这样使用Foreach-Object

$hash | Foreach-Object {@{System=$_.System;Job=$_.Job;Result="Good"}}

或者直接在子表达式中引用$hash:

${@{System=$hash.System;Job=$hash.Job;Result="Good"}}

但是,当我只处理一个哈希表时,使用 Foreach-Object 似乎很荒谬,并且非常冗长地提及两次我只想通过的属性,然后如果我的 $hash变量是$aSignificantlyLongerHashTableVariableName

如果我使用的是 Powershell 对象...

如果我使用这样的对象:

>$obj

System        Job                                      Result
------        ---                                      ---
server-1      Microsoft.PowerShell.Commands.PSWmiJob             

我会像这样使用select-object Cmdlet:

>$obj | Select-Object System, Job, @{Name="Result";Expression="Good"}

这会导致

>$obj

System        Job                                      Result
------        ---                                      ---
server-1      Microsoft.PowerShell.Commands.PSWmiJob   Good

Hashtable 和 PSObject 有一些相似的方面(以命名方式包含其他东西的东西),但是 AFAIK,它们不兼容 - 对于我在这里尝试做的事情,是否有更接近 Select-Object 的替代方案?

【问题讨论】:

    标签: powershell hash powershell-4.0 select-object


    【解决方案1】:

    严格要求将其作为单行程序,事先没有设置代码并且不修改源哈希,这样可以完成这项工作:

    ($hash + @{ 'Result' = 'Good' }).GetEnumerator() | ? {$_.Key -in 'Result','System','Job'}
    

    如果您要定期添加Result = Good,保存您的小扩展位可能会很方便:

    $good = @{ 'Result' = 'Good' }
    

    然后你的单行变成:

    ($hash + $good).GetEnumerator() | ? {$_.Key -in 'Result','System','Job'}
    

    编辑:正如您在下面的 cmets 中所指出的,如果 Result 存在于哈希中,则该单行将死亡。这个版本更安全/更明确,更直接地映射到你在 PSObjects 上用Select-Object 描述的精神:

    (($hash).GetEnumerator() | ? {$_.Key -in 'System','Job'}) + @{'Result' = 'Good'}
    

    仍然不是世界上最漂亮的东西,但它可以胜任。

    【讨论】:

    • 如果没有在代码中尝试,如果已经有一个名为Result 的键,这不会窒息吗?不过,到目前为止,您的答案是最有用的,非常感谢!
    • 最接近有用的,哈哈。这就是梦想!如果Result 已经存在,我的例子肯定会窒息。在这种情况下,您可以将其改组为 (($hash).GetEnumerator() | ? {$_.Key -in 'System','Job'}) + @{'Result' = 'Good'}
    • 理论上我不介意它是否修改了哈希,只要它不修改某些选定的值。显然,一个缺点可能是如果它慢 10 倍或更多倍,例如,将其放入对象中,修改它,然后将其放回哈希表中。 ---- 我的问题确实以Result 键开头,所以我可能会认为你评论中的表达式是一个答案,如果它被放入你的答案正文中。
    • 我已经编辑了答案(但将原始部分留在了那里,因为我认为单步执行它很有用)。在与你一起踢它并考虑更多之后,最后一条线确实感觉是正确的选择。不修改源是个好主意,主动避免关键冲突才有意义。
    【解决方案2】:

    要解析单值对象,请使用:

    $hash = @{}
    $hash.Add("System",$obj.System)
    $hash.Add("Job"=$obj.job)
    $hash.Add("Result"="Good")
    

    如果您需要更多对象 - 迭代它们 foreach($o in $obj){$hash.Add()},但在循环之前宣布 $hash。

    【讨论】:

    • 我不确定这如何回答我的问题(也许我没有问清楚?)——我有一个哈希表,坦率地说,它像一个对象一样被使用。我想以内联/管道方式在该哈希表中设置几个值。您的建议似乎是从一个对象开始的,它不是内联的,并且与我表示有兴趣避免的一种方法相比并没有特别的不同 - 我将尝试在我的问题中澄清。
    • 哦,是的。它将在脚本中工作,而不是在单个衬里 =(
    【解决方案3】:

    当您使用 Select-Object 并添加一个不存在的列(属性)时,您实际上是在创建一个新的 [PSObject] 来包装原始列。您可以通过两种方式显式执行此操作并使用[hashtable] 来启动其属性:

    $obj = [PSCustomObject]$hash
    

    $obj = New-Object PSObject -Property $hash
    

    从那里,您可以像往常一样使用Select-Object。您也可以先操作哈希以获得所需的属性,然后转换为对象并跳过Select-Object

    【讨论】:

    • 谢谢 - 我知道其中一个结构,但就内联使用此策略而言,假设我之后需要一个哈希表,那么有没有办法从一个对象?
    • @CodeJockey 没有单一的语言结构可以做到这一点,不,但您可以迭代对象的属性并创建一个:$hash = $obj.PSObject.Properties | % -Begin { $h = @{} } -Process { $h.Add($_.Name,$_.Value) | Out-Null } -End { $h }(这是来自内存,可能需要调整)。跨度>
    【解决方案4】:

    如果您只需要在哈希表中添加或更新键:

    $hash.Result += '好'

    如果 Result 键存在,它的值将设置为“Good”。如果它不存在,则会添加该值。

    【讨论】:

    • 这可以内联吗? - 我不这么认为...(?) - 基本上,我正在寻找哈希表的 select-object 的等价物,它将从哈希表开始,可能通过管道传输到命令或转换中,其中一个或修改更多字段,然后在同一语句中使用不同的字段
    • 不是内联的,但似乎没有任何好的答案,因为你想要做的是避免让 Powershell 管道做它设计做的事情 - 使用对象。
    • 就我而言,这就是我们所做的。但是,对于那些出于某种原因无法更改整个脚本(或脚本)并且必须以哈希表开头和结尾的人,我仍然想知道最佳答案。不过,我想总是可以选择不做内联的事情。
    • 内联代码是一种经常被实践的约定,因为它通常是人们从命令行学习使用 Powershell 的方式。一旦任务变得足够复杂以至于需要编写脚本,它就不会真正提供任何优势,而且通常只会导致代码更难阅读、维护或调试。
    猜你喜欢
    • 2016-12-23
    • 2013-05-23
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    相关资源
    最近更新 更多