Инициализация файла INI в PowerShell
Я разбираю простой (без разделов) INI файл в PowerShell. Вот код, который я придумал, есть ли способ его упростить?
convertfrom-stringdata -StringData ( `
get-content .\deploy.ini `
| foreach-object `
-Begin { $total = "" } `
{ $total += "`n" + $_.ToString() } `
-End { $total } `
).Replace("\", "\\")
Ответы
Ответ 1
После поиска в Интернете по этой теме я нашел несколько решений. Все они представляют собой ручной анализ файлов, поэтому я отказался от попыток сделать стандартные командлеты для выполнения этой задачи. Есть причудливые решения, такие как this, которые поддерживают сценарий написания.
Есть более простые, и насколько мне не нужна поддержка записи, я выбрал следующий очень элегантный фрагмент кода:
Function Parse-IniFile ($file) {
$ini = @{}
# Create a default section if none exist in the file. Like a java prop file.
$section = "NO_SECTION"
$ini[$section] = @{}
switch -regex -file $file {
"^\[(.+)\]$" {
$section = $matches[1].Trim()
$ini[$section] = @{}
}
"^\s*([^#].+?)\s*=\s*(.*)" {
$name,$value = $matches[1..2]
# skip comments that start with semicolon:
if (!($name.StartsWith(";"))) {
$ini[$section][$name] = $value.Trim()
}
}
}
$ini
}
Этот Jacques Barathon.
Обновление Благодаря Aasmund Eldhuset и @msorens для улучшений: обрезка пробелов и поддержка комментариев.
Обновить 2 Пропустить любые пары name=value
, где name
начинается с точки с запятой ;
, которая представляет собой строки комментариев. Замените $ini [$section] = @{}
на $ini[$section] = @{}
.
Ответ 2
Дон Джонс почти все понял. Попробуйте:
ConvertFrom-StringData((Get-Content .\deploy.ini) -join "`n")
-join
преобразует Object [] в одну строку, причем каждый элемент массива разделяется символом новой строки char. ConvertFrom-StringData
затем анализирует строку в пары ключ/значение.
Ответ 3
Это действительно расширение для текущего ответа (похоже, не добавляет комментарий).
Я испортил это, чтобы выполнить рудиментарную обработку целых чисел и десятичных знаков...
function Parse-IniFile ($file)
{
$ini = @{}
switch -regex -file $file
{
#Section.
"^\[(.+)\]$"
{
$section = $matches[1].Trim()
$ini[$section] = @{}
continue
}
#Int.
"^\s*([^#].+?)\s*=\s*(\d+)\s*$"
{
$name,$value = $matches[1..2]
$ini[$section][$name] = [int]$value
continue
}
#Decimal.
"^\s*([^#].+?)\s*=\s*(\d+\.\d+)\s*$"
{
$name,$value = $matches[1..2]
$ini[$section][$name] = [decimal]$value
continue
}
#Everything else.
"^\s*([^#].+?)\s*=\s*(.*)"
{
$name,$value = $matches[1..2]
$ini[$section][$name] = $value.Trim()
}
}
$ini
}
Ответ 4
Одна из возможностей - использовать библиотеку .NET ini. Nini, например.
Я перевел Простой пример из документов Nini в PowerShell ниже. Вы должны поместить nini.dll в тот же каталог, что и script.
$scriptDir = Split-Path -parent $MyInvocation.MyCommand.Definition
Add-Type -path $scriptDir\nini.dll
$source = New-Object Nini.Config.IniConfigSource("e:\scratch\MyApp.ini")
$fileName = $source.Configs["Logging"].Get("File Name")
$columns = $source.Configs["Logging"].GetInt("MessageColumns")
$fileSize = $source.Configs["Logging"].GetLong("MaxFileSize")
Ответ 5
Я не совсем уверен, как выглядят ваши исходные данные или какая у вас цель. Для чего вы разбираетесь? Можете ли вы опубликовать образец файла? Как есть, похоже, что вы просто конкатенируете возврат каретки к существующим строкам файла и заменяете\на \.
Непонятно, почему вы используете $_.ToString()
, поскольку $_
уже является строковым объектом, выводимым Get-Content.
Является ли цель просто взять файл, содержащий пару пар name = value, и преобразовать его в хеш-таблицу? То, что делает ConvertFrom-StringData
, хотя этот командлет доступен только в предварительном просмотре PowerShell v2.
Если ваш файл выглядит как...
key1=value1
key2=value2
key3=value3
Тогда вам понадобится
ConvertFrom-StringData (Get-Content .\deploy.ini)
Я не уверен, что понимаю, почему вы используете дополнительные возвраты каретки. Также нет необходимости использовать параметры -Begin
и -End
, по крайней мере, не настолько, насколько я могу видеть из того, что вы опубликовали.
Ответ 6
Я оптимизировал это решение для моих нужд, добавляя некоторые функции к функции и новую функцию для записи ini файла:
- Я сделал упорядоченный словарь из исходного словаря (хеш-таблицы), чтобы иметь возможность сохранить структуру файла
- И чтобы сохранить комментарии и пустые строки, я помещаю их в специальный ключ. Затем они могут игнорироваться при использовании данных или отбрасываться при записи в файл, как показано ниже в функции
Set-IniFile
- В
Set-IniFile
с использованием опций -PrintNoSection
и -PreserveNonData
его можно контролировать, если NO_SECTION следует использовать, и если необходимо сохранить строки без данных (не соответствующие key = value или [section].
Function Get-IniFile ($file) # Based on "/questions/388341/ini-file-parsing-in-powershell/1769169#1769169"
{
$ini = [ordered]@{}
# Create a default section if none exist in the file. Like a java prop file.
$section = "NO_SECTION"
$ini[$section] = [ordered]@{}
switch -regex -file $file
{
"^\[(.+)\]$"
{
$section = $matches[1].Trim()
$ini[$section] = [ordered]@{}
}
"^\s*(.+?)\s*=\s*(.*)"
{
$name,$value = $matches[1..2]
$ini[$section][$name] = $value.Trim()
}
default
{
$ini[$section]["<$("{0:d4}" -f $CommentCount++)>"] = $_
}
}
$ini
}
Function Set-IniFile ($iniObject, $Path, $PrintNoSection=$false, $PreserveNonData=$true)
{ # Based on "http://www.out-web.net/?p=109"
$Content = @()
ForEach ($Category in $iniObject.Keys)
{
if ( ($Category -notlike 'NO_SECTION') -or $PrintNoSection )
{
# Put a newline before category as seperator, only if there is none
$seperator = if ($Content[$Content.Count - 1] -eq "") {} else { "`n" }
$Content += $seperator + "[$Category]";
}
ForEach ($Key in $iniObject.$Category.Keys)
{
if ( $Key.StartsWith('<') )
{
if ($PreserveNonData)
{
$Content += $iniObject.$Category.$Key
}
}
else
{
$Content += "$Key = " + $iniObject.$Category.$Key
}
}
}
$Content | Set-Content $Path -Force
}
### EXAMPLE
##
## $iniObj = Get-IniFile 'c:\myfile.ini'
##
## $iniObj.existingCategory1.exisitingKey = 'value0'
## $iniObj['newCategory'] = @{
## 'newKey1' = 'value1';
## 'newKey2' = 'value2'
## }
## $iniObj.existingCategory1.insert(0, 'keyAtFirstPlace', 'value3')
## $iniObj.remove('existingCategory2')
##
## Set-IniFile $iniObj 'c:\myNewfile.ini' -PreserveNonData $false
##
Ответ 7
nini выглядит как библиотека... не уверен в powershell
сбой powerhell
первый шаг
[void][system.reflection.assembly]::loadfrom("nini.dll") (refer add-type now in ps2 )
после его использования
$iniwr = new-object nini.config.iniconfigsource("...\ODBCINST.INI")
$iniwr.Configs et boom