我可以从内部循环中引用外部循环中的迭代$ _值吗?

时间:2015-01-20 23:03:00

标签: powershell

出于演示目的,我有一个JSON文档,列出了各大洲和每个大洲的一些国家:

$json = ConvertFrom-Json '[{"Continent" : "Europe","Countries" : ["UK","France","Germany"]},
                           {"Continent" : "Africa","Countries" : ["Mali","Malawi","Nigeria"]}]' 

如果我想获得其中所有国家/地区的列表,我可以通过在foreach cmdlet中滚动两次来在一行PowerShell中执行此操作:

$json | foreach {$_.Countries} | foreach {$_ | Select @{Name="Country";Expression={$_}}}
Country                                                               
------- UK                                                                     France                                                                 Germany                                                                Mali                                                                   Malawi                                                                 Nigeria

一切都很正常。但是,如果我也想选择每个国家的大陆,那么我需要一个多语句脚本块:

$json | foreach {
    $Continent = $_.Continent
    $_.Countries | foreach {
                            $_ | Select-Object @{Name="Continent";Expression={$Continent}},@{Name="Country";Expression={$_}}
                           }
} 
Continent     Country
---------     ------- 
Europe        UK      
Europe        France  
Europe        Germany 
Africa        Mali    
Africa        Malawi  
Africa        Nigeria

我喜欢PowerShell的简洁性,所以在第二个例子中,我略微贬低了我需要将迭代的大陆存储在变量中的事实。我想知道的是,我可以做得更好吗?我可以做到更好吗?有没有办法在Select-Object的调用中引用外循环中的迭代值?

这就是全部,基本上只是想了解有关PowerShell及其可以做什么的更多信息。

2 个答案:

答案 0 :(得分:2)

您无法直接访问外部$_的值,但可以使用param捕获其值:

param($x=$_)

这将使您在技术上将所有内容都放在一行:

$json | foreach { param($x=$_) $_.Countries | foreach { $_ | Select-Object @{Name="Continent";Expression={$x.Continent}},@{Name="Country";Expression={$_}}}}

您还可以使用一些标准别名(即%foreachselectSelect-Object)来缩小代码大小:

$json | % { param($x=$_) $_.Countries | % { $_ | select @{Name="Continent";Expression={$x.Continent}},@{Name="Country";Expression={$_}}}}

但我只是建议在控制台中快速运行。将打包和重新打包的代码放入生产中只是简单的邪恶。 ;)

答案 1 :(得分:1)

我认为不可能获得“外部”$_。而且,即使你可以,我认为这不是一个好主意。

您可以使用Get-Variable -Scope 1在Powershell中引用父作用域(递归),其中1是直接父级,但这似乎不适用于嵌套的ForEach-Object调用。有关详细信息,请参阅about_Scopes

总的来说,在我看来,编码的可读性更好。

如果您被多语句块所困扰的主要原因是将其放在多行上,您可以将语句与;分开,以使它们保持在同一行。

$json | foreach { $Continent = $_.Continent ; $_.Countries | foreach { $_ | Select-Object @{Name="Continent";Expression={$Continent}},@{Name="Country";Expression={$_}} }} 

就个人而言,我更喜欢它分手了。