Я выполняю командлет PS 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 в нем, например {{X4} } и хотят рассматривать только те значения, которые имеют целочисленное значение после vol

Я использую следующий командлет, но он генерирует неправильный вывод ABC-volDAV

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

Мой вывод должен быть ABC-vol003

-2
meallhour 21 Авг 2018 в 00:30

4 ответа

Лучший ответ

Вы имеете в виду это?

$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]+' } |
  Sort-Object { [Int] $_.FreeSpaceGB } -Descending |
  Select-Object -First 1

Вышеуказанные выводы это:

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

Итак, здесь мы создаем вычисляемое свойство (пользовательский столбец) в выходном объекте, содержащем номер тома (извлеченный с помощью регулярного выражения), и сортируем по нему.

2
Bill_Stewart 21 Авг 2018 в 13:37

У тебя когда-нибудь было больше 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
0
Jordan 20 Авг 2018 в 22:18

Я хотел добавить ответ, который был бы больше ориентирован на PowerShell и содержал меньше регулярных выражений.

Я использую регулярное выражение в фильтре только для проверки, является ли строка всеми числами, потому что, насколько я знаю, в PowerShell нет стандартного командлета или метода для этого.

Это передаст данные примера, отфильтрует что-либо без vol в имени, затем проверит каждое из них, чтобы убедиться, что оно содержит только цифры в последних трех символах. Он делает это путем создания переменной из трех последних символов ($ matchString) с помощью метода .SubString, а затем пытается сопоставить ее со строкой регулярных выражений вуду, $ filterMatchOnlyNumbers.

Он будет передавать только объекты, которые соответствуют фильтру. Затем он сохраняет все это в $ результатов.

# 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

Я сохранил часть выбора только самого высокого результата для последнего, используя простую трубу для сортировки, затем выбрал.

«Sort Name -Descending» сортирует его по имени и сортирует по убыванию, так что наибольшее значение будет первым.

«Select Name» вернет только часть «Name» объектов в конвейере, а «Select -First 1» вернет только первую вещь, переданную в конвейере.

Я знаю, что все эти ответы немного похожи, но я хотел предоставить ответ, который был бы более энергичным и разнесенным для любых новичков, которые придут после этого.

0
Rob Traynere 20 Авг 2018 в 22:56

Продолжение ответа @ 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
0
veefu 21 Авг 2018 в 04:54
51938758