Contents of this directory is archived and no longer updated.

Тут обнаружился один интересный командлет – ConvertFrom-StringData, который позволяет преобразовывать строку в хэш-таблицы. Скажем, есть файл вида:

ключ1 = значение1
ключ2 = значение2
ключ3 = значение3
ключ4 = значение4

при этом иногда очень хочется работать с этими строками как с объектами. Т.е. при указании объекта и его ключа, например, $a.key1 получить его значение. Как это делается в хэш-таблицах. Вот пример:

[vPodans] $a = @{"key1"="value1";"key2"="value2"} [vPodans] $a Name Value ---- ----- key2 value2 key1 value1 [vPodans] $a.key1 value1 [vPodans] $a.key2 value2 [vPodans]

здесь я создал простую хэш-таблицу. Но если у нас есть файл общего вида, ключ = значение, то его можно легко привести в вид хэш-таблиц:

[vPodans] $a = "key1 = value1" [vPodans] $a key1 = value1 [vPodans] $a.GetType().FullName System.String [vPodans] $b = ConvertFrom-StringData -StringData $a [vPodans] $b Name Value ---- ----- key1 value1 [vPodans] $b.GetType().FullName System.Collections.Hashtable [vPodans] $b.key1 value1 [vPodans]

сперва я создал строку, которая состоит из пары ключ = значение, в чём мы можем убедиться в типе данных. Вторым этапом я сконвертировал эту строку в хэш-таблицу. Однако, следует учесть, что такое возможно только для строки, но не массива строк. Вот так легко попасть в засаду:

[vPodans] $a = gc keys.txt [vPodans] $a key1 = value1 key2 = value2 key3 = value3 key4 = value4 [vPodans] $a[0] key1 = value1 [vPodans] ConvertFrom-StringData -StringData $a ConvertFrom-StringData : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'StringData '. Specified method is not supported. At line:1 char:35 + ConvertFrom-StringData -StringData <<<< $a + CategoryInfo : InvalidArgument: (:) [ConvertFrom-StringData], ParameterBindingException + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ConvertFromStringDataCommand [vPodans]

командлет Get-Content (или его алиас GC, не путать с глобальным каталогом) читает файл построчно в виде массива. Следовательно каждая строка является отдельным элементом массива. Как быть в такой ситуации? На первый взгляд может показаться, что можно Get-Content разобрать через Foreach-Object и уже отдельные элементы массива подавать конвертеру в качестве строк. Смотрим:

[vPodans] $a = gc keys.txt | %{ConvertFrom-StringData -StringData $_} [vPodans] $a Name Value ---- ----- key1 value1 key2 value2 key3 value3 key4 value4 [vPodans] $a.key1 [vPodans] $a.GetType().FullName System.Object[] [vPodans] $a[0].key1 value1 [vPodans]

Как видите, мы на выходе получили не одну хэш-таблицу, а массив одиночных хэш-таблиц и для доступа к его ключам и значениям нужно ещё указывать номер элемента в массиве. Чтобы решить данную проблему нужно каким-то образом прочитать файл не построчно, а в виде целой строки. Для чтения файла целиком можно воспользоваться методом ReadAllText класса File Class. Как видно из описания метода, он читает текст в единую строку. Давайте посмотрим, что у нас получится:

[vPodans] $a = [io.file]::ReadAllText("keys.txt") [vPodans] $a key1 = value1 key2 = value2 key3 = value3 key4 = value4 [vPodans] $a.GetType().FullName System.String [vPodans] $b = ConvertFrom-StringData -StringData $a [vPodans] $b Name Value ---- ----- key2 value2 key4 value4 key1 value1 key3 value3 [vPodans] $b.key1 value1 [vPodans] $b.key2 value2 [vPodans] $b.key3 value3 [vPodans] $b.key4 value4 [vPodans]

или просто в одну строчку:

ConvertFrom-StringData -StringData ([io.file]::ReadAllText("keys.txt"))

Вот так просто в стиле The PowerShell Way (в одну строчку) можно текстовые файлы сконвертировать в хэш-таблицы и работать с ними как с объектами, что есть удобно и полезно.


Share this article:

Comments:

shs

Хорошобы сделать на его основе парсер ini-файла (если это возможно, конечно: как эта штука обрабатывает наличие секций [bla-bla-bla]?) "Тут обнаружился один интересный командлет – ConvertFrom-StringData, который позволяет преобразовывать строку в хэш-таблицы." Да, а где его он обнароужился? у меня такого нет: PS > Get-Command ConvertFrom-* CommandType Name Definition ----------- ---- ---------- Cmdlet ConvertFrom-SecureString ConvertFrom-SecureString [-SecureString] <Secure... PS > Get-Host Name : ConsoleHost Version : 1.0.0.0 InstanceId : 4f8b8376-a775-4fcd-a172-3685ea74d7a6 UI : System.Management.Automation.Internal.Host.InternalHostUserInterface CurrentCulture : ru-RU CurrentUICulture : ru-RU PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy

Vadims Podāns

>Да, а где его он обнароужился? у меня такого нет его нету в 1.0, он есть только в V2. [vPodans] gcm ConvertFrom-* CommandType Name Definition ----------- ---- ---------- Cmdlet ConvertFrom-Csv ConvertFrom-Csv [-InputObject] <PSObject[]> [[-D... Cmdlet ConvertFrom-SecureString ConvertFrom-SecureString [-SecureString] <Secure... Cmdlet ConvertFrom-StringData ConvertFrom-StringData [-StringData] <String> [-... как видно, в V2 добавился ещё ConvertFrom-Csv. Сейчас добавлю категорию V2, чтобы не было больше путаницы. > Хорошобы сделать на его основе парсер ini-файла парсер - на сколько это актуально? Секции [bla-bla-bla] она не обрабатывает никак, а валится с ошибкой. Поэтому я вижу только один вариант: задавать имя секции - регулярными выражениями распарсить название, собрать все данные до следующей секции [bla-bla-bla] и эти данные уже пропускать через командлет. Нативной поддержки парсинга INI файлов по секциям нету.

shs

>парсер - на сколько это актуально? Парсить ini'шники бывает необходимо, когда работаетшь с приложениями, где их много, например MDaemon или пишешь скрипт с большим ко-вом параметров (в этом случае использовать параметры ком строки неудобно, по понятным причинам), использовать реестр так же не хотелось бы, т.к. все-таки проще открыть файл в блокноте и что-то в нем исправить, нежели добираться всякий раз до нужной ветки реестра, рискуя "задеть что-нить по дороге, да и при переносе с компа на комп такого скрипта это добавит лишних телодвижений.

Vadims Podāns

А что должен уметь делать этот парсер? Если можно, по пунктам. Я подумаю над решением.

Comments are closed.