出于演示目的,我有一个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及其可以做什么的更多信息。
答案 0 :(得分:2)
您无法直接访问外部$_
的值,但可以使用param
捕获其值:
param($x=$_)
这将使您在技术上将所有内容都放在一行:
$json | foreach { param($x=$_) $_.Countries | foreach { $_ | Select-Object @{Name="Continent";Expression={$x.Continent}},@{Name="Country";Expression={$_}}}}
您还可以使用一些标准别名(即%
为foreach
而select
为Select-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={$_}} }}
就个人而言,我更喜欢它分手了。