Анализ файла INI в PowerShell - PullRequest
15 голосов
/ 06 января 2009

Я анализирую простой (без разделов) INI-файл в PowerShell. Вот код, который я придумал, есть ли способ упростить его?

convertfrom-stringdata -StringData ( `
  get-content .\deploy.ini `
  | foreach-object `
    -Begin { $total = "" }  `
    { $total += "`n" + $_.ToString() } `
    -End { $total } `
).Replace("\", "\\")

Ответы [ 7 ]

27 голосов
/ 08 января 2009

После поиска в интернете по этой теме я нашел несколько решений. Все они - ручной анализ файловых данных, поэтому я перестал пытаться создавать стандартные командлеты для выполнения этой работы. Есть такие причудливые решения, как 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
}

Это Жак Барафон .

Обновление Спасибо Aasmund Eldhuset и @msorens за улучшения: обрезка пробелов и поддержка комментариев.

Обновление 2 Пропускать любые пары name=value, где name начинается с точки с запятой ;, которые являются строками комментария . Заменено $ini [$section] = @{} на $ini[$section] = @{}.

9 голосов
/ 22 ноября 2011

Дон Джонс почти все понял. Попробуйте:

ConvertFrom-StringData((Get-Content .\deploy.ini) -join "`n")

-join преобразует Object [] в одну строку, где каждый элемент массива отделяется символом новой строки. ConvertFrom-StringData затем разбирает строку на пары ключ / значение.

5 голосов
/ 13 июля 2011

Это действительно расширение к текущему ответу (кажется, не может добавить комментарий).

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

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
}
2 голосов
/ 22 ноября 2010

Одна из возможностей - использовать библиотеку INI .NET. Нини например.

Я перевел Простой пример из документации Nini в PowerShell ниже. Вам нужно положить nini.dll в ту же директорию, что и скрипт.

$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")
1 голос
/ 23 февраля 2016

Я оптимизировал это решение для своих нужд, добавив некоторые функции и новую функцию для записи ini-файла:

  1. Я сделал упорядоченный словарь из исходного словаря (хэш-таблицы), чтобы иметь возможность сохранить структуру файла
  2. А чтобы сохранить комментарии и пустые строки, я помещаю их в специальный ключ. Затем их можно игнорировать при использовании данных или выбрасывать при записи в файл, как показано ниже в функции Set-IniFile
  3. В Set-IniFile с использованием параметров -PrintNoSection и -PreserveNonData можно контролировать, следует ли использовать NO_SECTION и сохранять ли строки без данных (не соответствующие ключу = значению или [разделу].

Function Get-IniFile ($file)       # Based on "https://stackoverflow.com/a/422529"
 {
    $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
##
1 голос
/ 07 января 2009

Я не совсем уверен, как выглядят ваши исходные данные или какова ваша цель. Что именно вы анализируете? Можете ли вы опубликовать образец файла? Как есть, похоже, что вы просто объединяете возврат каретки к существующим строкам файла и заменяете \ на \.

Не уверен, почему вы используете $_.ToString(), поскольку $_ уже является строковым объектом, выводимым Get-Content.

Является ли целью просто взять файл, содержащий несколько пар имя = значение, и преобразовать его в хеш-таблицу? Это то, что делает ConvertFrom-StringData, хотя этот командлет доступен только в предварительном просмотре PowerShell v2.

Если ваш файл выглядит так ...

key1=value1
key2=value2
key3=value3

Тогда все, что вам нужно, это

ConvertFrom-StringData (Get-Content .\deploy.ini)

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

0 голосов
/ 24 октября 2011

nini выглядит как библиотека ... не уверен в powershell

сбой PowerShell

первый шаг

[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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...