Как построить хеш-таблицу из файла с помощью powershell?

У меня есть файл, в котором компонент Baseline и имена компонентов хранятся следующим образом

(Mailcomp@\My_PVOB) BL_2.1.0.9.5179@\My_PVOB
(OfficeComp@\My_PVOB) BL_2.1.0.17.6972@\MY_PVOB

На самом деле мне нужно построить хэш-таблицу, которая может иметь такие записи, как

@(Key=Mailcomp,Value=BL_2.1.0.9.5179)
@(Key=OfficeComp, Value=BL_2.1.0.17.6972)

Я пытался заменить следующим образом

(Get-Content $BaselineFile) | foreach{ $_ -replace "@\My_PVOB[?]",''} | Out-File  $BaselineFile

Затем я попытался создать хеш-таблицу, но первая команда не удалась, и я не знаю, как создать хеш-таблицу из файловых записей. Может кто-то мне помочь, пожалуйста?


person Samselvaprabu    schedule 06.01.2012    source источник


Ответы (3)


На момент написания есть два ответа (один от Шей Леви и один от Джона Зи), которые оба близки, но ни один из них не совсем правильный, несмотря на то, что ответ Шэя уже был принят (!). Вот почему:

Проблемы с кодом Шэя

Ответ Шэя слишком буквальный, основанный на неточно сформулированном требовании, которое указывает на создание «хэш-таблицы, в которой могут быть такие записи»:

@(Key=Mailcomp,Value=BL_2.1.0.9.5179)
@(Key=OfficeComp, Value=BL_2.1.0.17.6972)

Но если кто-то собирается использовать синтаксис PowerShell, это указано неверно. Требование в реальности должно выглядеть так:

@{Mailcomp=BL_2.1.0.9.5179}
@{OfficeComp=BL_2.1.0.17.6972}

Другими словами, первая строка определяет хеш-ключ Mailcomp и хэш-значение BL_2.1.0.9.5179. Эта модифицированная версия кода Шэя обеспечивает именно это:

$hash = @{}
Get-Content $BaselineFile | 
Foreach-Object {
    if ($_ -match '^\(([^@]+).+\)\s([^@]+)')
    {
        $hash[$matches[1]]=$matches[2]
    }
}

Вот результат:

Name       Value
----       -----
Mailcomp   BL_2.1.0.9.5179
OfficeComp BL_2.1.0.17.6972

С этим намного проще работать, так как теперь я могу получить доступ к $hash["Mailcomp"] или $hash["OfficeComp"] для получения соответствующих значений.

Вторая проблема с кодом Шэя — это само создание хеш-записи (@{ key=$matches[1]; value=$matches[2] }). Этот оператор создает отдельную "мини" хеш-таблицу для каждой итерации (т.е. для каждой строки ввода). Кажется, он выдает приемлемый результат только из-за объединения неявного Write-Output в его коде. Чтобы доказать это — и сравнить яблоки с яблоками — возьмите мой код выше и замените условное выражение на этот, эквивалентный коду Шэя:

    if ($_ -match '^\(([^@]+).+\)\s([^@]+)')
    {
        @{ $matches[1]=$matches[2] }
    }

Вы обнаружите, что $hash["Mailcomp"] не возвращает ожидаемое BL_2.1.0.9.5179.

Проблемы с кодом Джона

Мне нравится ответ Джона Зи; Я действительно. Действительно. Но это напоминает мне старый добрый анекдот с изюминкой предположим, что у нас есть консервный нож. .. Это очень хорошее решение тогда и только тогда, когда ввод поддается простому разделителю. Здесь дело обстоит иначе — для массажа ввода требуется регулярное выражение (или другой механизм). Честно говоря, Джон отмечает, что явно заявляя, что он предполагает некоторую предварительную обработку. — сказал Нафф.

person Michael Sorens    schedule 10.01.2012
comment
Я проверю и внесу необходимые изменения, приняв лучший ответ - person Samselvaprabu; 10.01.2012

Предполагая, что ваш $baselinefile после предварительной обработки выглядит так:

Mailcomp BL_2.1.0.9.5179
OfficeComp BL_2.1.0.17.6972

это должно работать:

$hash = @{}
Import-Csv $BaseLineFile -header "first", "second" -delimiter " " | ForEach-Object { $hash[$_.first] = $_.second}
$hash
person jon Z    schedule 06.01.2012

Попробуйте это:

Get-Content $BaselineFile | Foreach-Object { 
    if($_ -match '^\(([^@]+).+\)\s([^@]+)')
    {
        @{
            key=$matches[1]
            value=$matches[2]   
        }
    }
}

Name    Value
----    -----
value   BL_2.1.0.9.5179
key     Mailcomp
value   BL_2.1.0.17.6972
key     OfficeComp

Or

Get-Content $BaselineFile | Foreach-Object { 

    $value = ($_ -replace '@\\My_PVOB|\(|\)').split()

    @{
        key=$value[0]
        value=$value[1] 
    }
}

ОБНОВЛЕНИЕ: Создайте одну хеш-таблицу, хеш-ключ состоит из первого совпадения, а его значение — второе совпадение:

$ht = @{}

Get-Content $BaselineFile | Foreach-Object {     

    if($_ -match '^\(([^@]+).+\)\s([^@]+)')
    {        
            $ht[$matches[1]] = $matches[2]     
    }    
}

$ht

Name       Value           
----       -----           
Mailcomp   BL_2.1.0.9.5179 
OfficeComp BL_2.1.0.17.6972
person Shay Levy    schedule 06.01.2012
comment
И снова легкие для понимания ответы Леви потрясают. Это работает, приятель, и также понятно - person Samselvaprabu; 06.01.2012
comment
Это безымянный хэш. Как сохранить это в именованном хеше? Чтобы я мог обработать каждое значение в хеше и выполнить еще одну операцию - person Samselvaprabu; 06.01.2012
comment
Вы можете присвоить результат переменной и обработать каждый из них, используя индекс коллекции. например: $h = gc... а затем $h[0].key и т. д. - person Shay Levy; 06.01.2012
comment
Бадди, Как упоминает msorens, у вашего кода есть проблемы? Я использовал метод замены из вашего кода и остальные вещи, которые я использую от JonZ, и я не уверен в этой теории. - person Samselvaprabu; 10.01.2012