仅过滤PS输出中的特定值

时间:2018-08-20 21:30:03

标签: windows powershell powershell-v3.0 powershell-v4.0

我正在运行PS cmdlet get-customcmdlet,它将生成以下输出

Name                         FreeSpaceGB
----                         -----------
ABC-vol001                   1,474.201
ABC-vol002                   2,345.437     
ABC-vol003                   3,147.135
ABC-volDAV                   4,147.135
ABC-volCDA                   5,147.135

我想从最高的003 volume number捕获ABC-vol003,我也想忽略vol之后没有整数值的值,例如{ {1}},只想考虑其中ABC-volDAV之后有整数值的值

我正在使用以下cmdlet,但是它生成了错误的输出vol

ABC-volDAV

我的输出应为Get-CustomCmdlet | Where-Object Name -match vol | select Name | Sort {$_.Name -replace '.*?(\d+)$','$1'} -descending | Select -First 1

4 个答案:

答案 0 :(得分:2)

你是这个意思吗?

Name       FreeSpaceGB
----       -----------
ABC-vol003 3147.135

以上输出此:

$inputData = @"
"Name","FreeSpaceGB"
"ABC-vol001","1474.201"
"ABC-vol002","2345.437"     
"ABC-vol003","3147.135"
"ABC-volDAV","4147.135"
"@ | ConvertFrom-Csv

$inputData |
  Where-Object { $_.Name -match '-vol[\d]+' } |
  Select-Object `
    Name,
    @{Name = "Volume"; Expression = { [Regex]::Match($_.Name, '\d+$').Value }},
    FreeSpaceGB |
  Sort-Object Volume -Descending

基于评论-这是猜测提问者想要做什么的另一种尝试:

Name       Volume FreeSpaceGB
----       ------ -----------
ABC-vol003 003    3147.135  
ABC-vol002 002    2345.437  
ABC-vol001 001    1474.201

此代码输出以下内容:

{{1}}

所以在这里,我们在包含卷号(使用正则表达式提取)的输出对象中创建一个计算属性(自定义列),并以此进行排序。

答案 1 :(得分:0)

您是否有超过10卷?

Get-CustomCmdlet | ? Name -Notmatch ".*\d{3}$" | sort Name -Descending

否则

Get-CustomCmdlet | ? Name -match ".*\d{3}$" | sort {[int]($_.Name -replace "\w{3}-\w{3}","")} -Descending

答案 2 :(得分:0)

我想添加一个以PowerShell为中心且正则表达式较少的答案。

我仅在过滤器中使用正则表达式来测试字符串是否为全数字,因为据我所知,PowerShell中没有固定的cmdlet或方法可以执行此操作。

这将流水线处理示例数据,过滤掉名称中不包含vol的所有内容,然后测试每个以确保其后三个字符中只有数字。它通过使用.SubString方法创建最后三个字符($ matchString)的变量,然后尝试将其与正则表达式伏都教字符串$ filterMatchOnlyNumbers进行匹配。

它只会传递与过滤器匹配的对象。然后将所有内容保存到$ results中。

# example data set
$inputData = @"
"Name","FreeSpaceGB"
"ABC-vol001","1474.201"
"ABC-vol002","2345.437"     
"ABC-vol003","3147.135"
"ABC-volDAV","4147.135"
"ABC-volCDA","5147.135"
"ABC-volS4D","6147.135"
"@ | ConvertFrom-Csv

# regex voodoo to detect only numbers
$filterMatchOnlyNumbers = '^[\d\.]+$'

# filter to only return results that have "vol" in name
$nameFilter = '*vol*'

# do work and store to $results
$results = (
    $inputData |
    Where {$_.Name -like $nameFilter} |
    ForEach {
        # get last 3 characters of name
        $matchString = $_.Name.Substring($_.Name.Length - 3)

        If ($matchString -match $filterMatchOnlyNumbers){
            # pass this on if it is only numbers
            $_
        }
    }
)

# print results (only highest)
$results | Sort Name -Descending | Select Name -First 1

我保存了只选择“最高”结果的部分,最后使用一个简单的管道进行排序,然后选择。

“排序名称-降序”按名称对其进行排序,并按降序对其进行排序,以使最高的值排在第一位。

“选择名称”将仅返回管道中对象的“名称”部分,而“选择-第一1”将仅返回在管道中传递的第一件事。

我知道所有这些答案都有些相同,但是我想提供一个更强大的答案,并为以后出现的任何新手提供一定的空间。

答案 3 :(得分:0)

关注@Bill_Stewart的答案。保存“ VolumeID”以供以后参考似乎很有价值。这段代码通过Select-Object将其添加为计算字段,为您提供一个名称,以便稍后在管道中进行过滤和排序。

$inputData = @"
"Name","FreeSpaceGB"
"ABC-vol001","1474.201"
"ABC-vol002","2345.437"
"ABC-vol003","3147.135"
"ABC-volDAV","4147.135"
"ABC-volCDA","5147.135"
"ABC-volS4D","6147.135"
"@ | ConvertFrom-Csv


$inputdata | Select-Object -Property @(
        'Name'
        'FreeSpaceGB'
        @{l='VolumeID';e={$_.name -replace ".*-vol(.+).*",'$1'}}
    ) |
    Where-Object VolumeID -match "\d{3}" | 
    Sort-Object VolumeID | 
    Select-Object -Last 1

如果您不喜欢在Select-Object期间创建的额外属性,则可能需要使用正则表达式过滤器来制作函数以便于重新使用:

function GetVolumeID {
    process { $_.Name -replace ".*-vol(.+).*",'$1' }
}

$inputData |
    Where-Object { ($_ | GetVolumeID) -match "\d{3}"} |
    Sort-Object { $_ | GetVolumeID } |
    Select-Object -Last 1