对管道中的 Powershell 对象进行分组和排序
Group and rank Powershell objects in the pipeline
我正在尝试对 powerhell 管道中的一组对象进行排名。
Get-ChildItem "*.csv" |
Select-object fullname, Length, @{N = "Environment"; E = {
if ($_.fullname -like "*Dev*") {
"DEV"
}
elseif ($_.fullname -like "*PROD*") {
"PROD"
}
elseif ($_.fullname -like "*UAT*") {
"UAT"
}
}} | Sort-Object -Property Environment, Length
我想根据组(环境和长度)在管道中添加具有以下值的 Rank
属性。有没有像SQL ranking function
这样的内置powershell
FullName Length Environment Rank
-------- ------ ----------- ----
C:\Temp\ReportDEV-20171210_210653.csv 3065 DEV 1
C:\Temp\ReportDEV-20171210_211041.csv 9116 DEV 2
C:\Temp\ReportDEV-20171210_190100.csv 76286 DEV 3
C:\Temp\ReportDEV-20171210_200229.csv 511546 DEV 4
C:\Temp\ReportPROD-20171210_210349.csv 2835 PROD 1
C:\Temp\ReportPROD-20171210_210754.csv 8897 PROD 2
C:\Temp\ReportPROD-20171210_184729.csv 43850 PROD 3
C:\Temp\ReportPROD-20171210_191133.csv 213202 PROD 4
C:\Temp\ReportUAT-20171210_210554.csv 3065 UAT 1
C:\Temp\ReportUAT-20171210_210920.csv 9116 UAT 2
C:\Temp\ReportUAT-20171210_185308.csv 57244 UAT 3
C:\Temp\ReportUAT-20171210_193211.csv 306154 UAT 4
您可以使用 for 循环简单地将排名添加到输出对象。
ForEach-Object
接受脚本块作为第一个参数中的开始脚本。我用它来声明计数器,然后是用于处理脚本的第二个参数,除了创建所需的输出对象外,我还增加了计数器。
示例 1 - 行的行号:
Get-ChildItem "C:\SomeDirectory" -Recurse -File | Sort-Object Name |
ForEach-Object {$i = 1} {
New-Object psObject -Property @{Name= $_.Name; Rank= $i++;}
}
结果
Name Rank
---- ----
Product1-1.txt 1
Product1-2.txt 2
Product1-3.txt 3
Product2-1.txt 4
Product2-2.txt 5
示例 2 - 组中行的行号:
Get-ChildItem "C:\SomeDirectory" -Recurse -File | Group-Object DirectoryName |
ForEach-Object {
$_.Group | ForEach-Object {$i = 1} {
New-Object psObject -Property @{
GroupName= $_.Directory.Name; Name= $_.Name;Rank= $i++;
}
}
}
结果
GroupName Name Rank
--------- ---- ----
Category1 Product1-1.txt 1
Category1 Product1-2.txt 2
Category1 Product1-3.txt 3
Category2 Product2-1.txt 1
Category2 Product2-2.txt 2
遗憾的是,PowerShell 不提供开箱即用的排名功能,因此需要额外的工作:
$rank = 0
$prevEnv = ''
Get-ChildItem *.csv | Select-Object FullName, Length, @{
n='Environment'; e={ $_.Name -replace '.*(DEV|PROD|UAT).*', '' } } |
Sort-Object Environment, Length | Select-Object *, @{
n='Rank'; e={
++$rank
if ($prevEnv -ne $_.Environment) {
$rank = 1
Set-Variable -Scope 1 prevEnv $_.Environment
}
Set-Variable -Scope 1 rank $rank
$rank
}
}
注意在 .Environment
属性 中将输入文件名映射到环境名称的简化方法,使用 -replace
和正则表达式和捕获组来从文件名中提取感兴趣的标记。
通过Select-Object
添加.Environment
属性后,对象先按.Environment
排序,再按.Length
排序(文件大小(以字节为单位)。
然后通过另一个 Select-Object
调用为生成的对象提供 .Rank
属性,其值是基于 1
的序列号每当遇到新的 .Environment
值时都会重置,实际上相当于每个环境的文件大小排名。
注意需要 Set-Variable
才能修改 $rank
和 $prevEnv
变量,因为这些变量必须在管道范围内维护一个整体,以便它们在连续的 Select-Object
调用中持续存在(相比之下,例如,在分配给键 e
的脚本块内,一个本地 $rank
变量将被限定为该脚本仅块)。
或者,使用Group-Object
(更简洁,但效率较低):
Get-ChildItem *.csv | Select-Object FullName, Length, @{
n='Environment'; e={ $_.Name -replace '.*(DEV|PROD|UAT).*', '' }
} |
Group-Object Environment | ForEach-Object {
$rank = 0
$_.Group | Sort-Object Length | Select-Object *, @{
n='Rank'; e={ Set-Variable -Scope 1 rank ($rank+1); $rank }
}
}
Group-Object Environment
按新添加的 .Environment
属性.
对输入对象进行分组
ForEach-Object
然后遍历所有结果组。
- 每个组的 (
$_
) 个成员通过 .Group
属性 枚举,并按 .Length
. 排序
第二个 Select-Object
调用然后循环遍历长度排序的组成员并生成具有 .Rank
属性 反映基于 1 的扩充输出对象基于文件大小(长度)的组相对排名按升序排列。
注意需要 Set-Variable
来递增 $rank
变量,因为该变量必须在 ForEach-Object
主体级别维护存在于连续的 Select-Object
次调用中(在分配给键 e
的脚本块内,本地 $rank
变量的范围仅限于该脚本块)。
我正在尝试对 powerhell 管道中的一组对象进行排名。
Get-ChildItem "*.csv" |
Select-object fullname, Length, @{N = "Environment"; E = {
if ($_.fullname -like "*Dev*") {
"DEV"
}
elseif ($_.fullname -like "*PROD*") {
"PROD"
}
elseif ($_.fullname -like "*UAT*") {
"UAT"
}
}} | Sort-Object -Property Environment, Length
我想根据组(环境和长度)在管道中添加具有以下值的 Rank
属性。有没有像SQL ranking function
FullName Length Environment Rank
-------- ------ ----------- ----
C:\Temp\ReportDEV-20171210_210653.csv 3065 DEV 1
C:\Temp\ReportDEV-20171210_211041.csv 9116 DEV 2
C:\Temp\ReportDEV-20171210_190100.csv 76286 DEV 3
C:\Temp\ReportDEV-20171210_200229.csv 511546 DEV 4
C:\Temp\ReportPROD-20171210_210349.csv 2835 PROD 1
C:\Temp\ReportPROD-20171210_210754.csv 8897 PROD 2
C:\Temp\ReportPROD-20171210_184729.csv 43850 PROD 3
C:\Temp\ReportPROD-20171210_191133.csv 213202 PROD 4
C:\Temp\ReportUAT-20171210_210554.csv 3065 UAT 1
C:\Temp\ReportUAT-20171210_210920.csv 9116 UAT 2
C:\Temp\ReportUAT-20171210_185308.csv 57244 UAT 3
C:\Temp\ReportUAT-20171210_193211.csv 306154 UAT 4
您可以使用 for 循环简单地将排名添加到输出对象。
ForEach-Object
接受脚本块作为第一个参数中的开始脚本。我用它来声明计数器,然后是用于处理脚本的第二个参数,除了创建所需的输出对象外,我还增加了计数器。
示例 1 - 行的行号:
Get-ChildItem "C:\SomeDirectory" -Recurse -File | Sort-Object Name |
ForEach-Object {$i = 1} {
New-Object psObject -Property @{Name= $_.Name; Rank= $i++;}
}
结果
Name Rank
---- ----
Product1-1.txt 1
Product1-2.txt 2
Product1-3.txt 3
Product2-1.txt 4
Product2-2.txt 5
示例 2 - 组中行的行号:
Get-ChildItem "C:\SomeDirectory" -Recurse -File | Group-Object DirectoryName |
ForEach-Object {
$_.Group | ForEach-Object {$i = 1} {
New-Object psObject -Property @{
GroupName= $_.Directory.Name; Name= $_.Name;Rank= $i++;
}
}
}
结果
GroupName Name Rank
--------- ---- ----
Category1 Product1-1.txt 1
Category1 Product1-2.txt 2
Category1 Product1-3.txt 3
Category2 Product2-1.txt 1
Category2 Product2-2.txt 2
遗憾的是,PowerShell 不提供开箱即用的排名功能,因此需要额外的工作:
$rank = 0
$prevEnv = ''
Get-ChildItem *.csv | Select-Object FullName, Length, @{
n='Environment'; e={ $_.Name -replace '.*(DEV|PROD|UAT).*', '' } } |
Sort-Object Environment, Length | Select-Object *, @{
n='Rank'; e={
++$rank
if ($prevEnv -ne $_.Environment) {
$rank = 1
Set-Variable -Scope 1 prevEnv $_.Environment
}
Set-Variable -Scope 1 rank $rank
$rank
}
}
注意在 .Environment
属性 中将输入文件名映射到环境名称的简化方法,使用 -replace
和正则表达式和捕获组来从文件名中提取感兴趣的标记。
通过
Select-Object
添加.Environment
属性后,对象先按.Environment
排序,再按.Length
排序(文件大小(以字节为单位)。然后通过另一个
Select-Object
调用为生成的对象提供.Rank
属性,其值是基于1
的序列号每当遇到新的.Environment
值时都会重置,实际上相当于每个环境的文件大小排名。注意需要
Set-Variable
才能修改$rank
和$prevEnv
变量,因为这些变量必须在管道范围内维护一个整体,以便它们在连续的Select-Object
调用中持续存在(相比之下,例如,在分配给键e
的脚本块内,一个本地$rank
变量将被限定为该脚本仅块)。
或者,使用Group-Object
(更简洁,但效率较低):
Get-ChildItem *.csv | Select-Object FullName, Length, @{
n='Environment'; e={ $_.Name -replace '.*(DEV|PROD|UAT).*', '' }
} |
Group-Object Environment | ForEach-Object {
$rank = 0
$_.Group | Sort-Object Length | Select-Object *, @{
n='Rank'; e={ Set-Variable -Scope 1 rank ($rank+1); $rank }
}
}
Group-Object Environment
按新添加的.Environment
属性. 对输入对象进行分组
ForEach-Object
然后遍历所有结果组。- 每个组的 (
$_
) 个成员通过.Group
属性 枚举,并按.Length
. 排序
第二个
Select-Object
调用然后循环遍历长度排序的组成员并生成具有.Rank
属性 反映基于 1 的扩充输出对象基于文件大小(长度)的组相对排名按升序排列。注意需要
Set-Variable
来递增$rank
变量,因为该变量必须在ForEach-Object
主体级别维护存在于连续的Select-Object
次调用中(在分配给键e
的脚本块内,本地$rank
变量的范围仅限于该脚本块)。
- 每个组的 (