如何使用PowerShell使用从INI文件读取的值在模板字符串中展开占位符?

时间:2016-11-04 15:31:27

标签: powershell templates ini string-interpolation

values.ini 看起来像

[default]
A=1
B=2
C=3

foo.txt 看起来像

Now is the %A% for %a% %B% men to come to the %C% of their %c%

我想使用Powershell搜索 values.ini 中的所有%x%值,然后将 foo.txt 中的每个匹配实例替换为相应的值,不区分大小写;产生以下内容:

Now is the 1 for 1 2 men to come to the 3 of their 3

3 个答案:

答案 0 :(得分:2)

假设PowerShell 3.0或更高版本,您可以使用ConvertFrom-StringData cmdlet来解析ini文件中的键值对,但是您需要过滤掉[default]指令:

# grab relevant lines from file
$KeyValPairs = Get-Content .\values.ini | Where {$_ -like "*=*" }

# join strings together as one big string
$KeyValPairString = $KeyValPairs -join [Environment]::NewLine

# create hashtable/dictionary from string with ConvertFrom-StringData
$Dictionary = $KeyValPairString |ConvertFrom-StringData

然后,您可以使用[regex]::Replace()方法对要替换的每个匹配项进行字典查找:

Get-Content .\foo.txt |ForEach-Object { 
    [Regex]::Replace($_, '%(\p{L}+)%', {
        param($Match)

        # look term up in dictionary
        return $Dictionary[$Match.Groups[1].Value]
    }) 
}

答案 1 :(得分:1)

使用替代方法补充Mathias R. Jessen's excellent answer,同时考虑将限制值更改为特定INI文件部分的后续要求更改(PSv2 +,Get-Content -Raw除外;在PSv2中,请改用(Get-Content ...) -join "`n"。)

使用PsIni\Get-IniContent[environment]::ExpandEnvironmentVariables()

# Translate key-value pairs from section the section of interest
# into environment variables.
# After this command, the following environment variables are defined:
#     $env:A, with value 1 (cmd.exe equivalent: %A%)
#     $env:B, with value 2 (cmd.exe equivalent: %B%)
#     $env:C, with value 3 (cmd.exe equivalent: %C%)
$section = 'default'  # Specify the INI-file section of interest.
(Get-IniContent values.ini)[$section].GetEnumerator() | 
  ForEach-Object { Set-Item "env:$($_.Name)" -Value $_.Value }

# Read the template string as a whole from file foo.txt, and expand the
# environment-variable references in it, using the .NET framework.
# With the sample input, this yields
#  "Now is the 1 for 1 2 men to come to the 3 of their 3".
[environment]::ExpandEnvironmentVariables((Get-Content -Raw foo.txt))

第三方Get-IniContent cmdlet可以方便地将一个INI文件(*.ini)读入嵌套的有序散列表中,可以通过高架控制台轻松安装Install-Module PsIni(或者,如果您有PS v5 +(或安装了PackageManagement的v3或v4),请添加-Scope CurrentUser)。

此解决方案利用了占位符(例如%a%)看起来像cmd.exe样式的环境变量引用这一事实。

请注意假设和警告

  • 所有ini-file键/占位符名称都是合法的环境变量名称。
  • 可能会覆盖预先存在的变量,这可能会因PATH等名称而出现问题。
  • 跨平台警告:在类Unix平台上,环境变量引用区分大小写,因此解决方案不会在那里工作。

使用自定义INI文件解析和[environment]::ExpandEnvironmentVariables()

如果不能安装用于INI文件解析的模块,则以下解决方案使用 - 相当复杂 - 的正则表达式通过-replace运算符提取感兴趣的部分。

$section = 'default'  # Specify the INI-file section of interest.
# Get all non-empty, non-comment lines from the section using a regex.
$sectLines = (Get-Content -Raw values.ini) -replace ('(?smn)\A.*?(^|\r\n)\[' + [regex]::Escape($section) + '\]\r\n(?<sectLines>.*?)(\r\n\[.*|\Z)'), '${sectLines}' -split "`r`n" -notmatch '(^;|^\s*$)'
# Define the key-value pairs as environment variables.
$sectlines | ForEach-Object { $tokens = $_ -split '=', 2; Set-Item "env:$($tokens[0].Trim())" -Value $tokens[1].Trim() }

# Read the template string as a whole, and expand the environment-variable 
# references in it, as before. 
[environment]::ExpandEnvironmentVariables((Get-Content -Raw foo.txt))

答案 2 :(得分:-1)

我使用名为 Get-IniContent INI script找到了一个更简单的解决方案。

#read from Setup.ini
$INI = Get-IniContent .\Setup.ini
$sec="setup"

#REPLACE VARIABLES
foreach($c in Get-ChildItem -Path .\Application  -Recurse -Filter *.config)
{
  Write-Output $c.FullName
  Write-Output $c.DirectoryName

  $configFile = Get-Content $c.FullName -Raw
  foreach($v in $INI[$sec].Keys)
  {
    $k = '%'+$v+'%'
    $match = [regex]::IsMatch($configFile, $k)
    if($match)
    {
      $configFile = $configFile -ireplace [regex]::Escape($k), $INI[$sec][$v]
    }
  }
  Set-Content $c.FullName -Value $configFile 
}