Тут обнаружился один интересный командлет – 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 (в одну строчку) можно текстовые файлы сконвертировать в хэш-таблицы и работать с ними как с объектами, что есть удобно и полезно.
Хорошобы сделать на его основе парсер 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
>Да, а где его он обнароужился? у меня такого нет его нету в 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 файлов по секциям нету.
>парсер - на сколько это актуально? Парсить ini'шники бывает необходимо, когда работаетшь с приложениями, где их много, например MDaemon или пишешь скрипт с большим ко-вом параметров (в этом случае использовать параметры ком строки неудобно, по понятным причинам), использовать реестр так же не хотелось бы, т.к. все-таки проще открыть файл в блокноте и что-то в нем исправить, нежели добираться всякий раз до нужной ветки реестра, рискуя "задеть что-нить по дороге, да и при переносе с компа на комп такого скрипта это добавит лишних телодвижений.
А что должен уметь делать этот парсер? Если можно, по пунктам. Я подумаю над решением.
Comments: