假设我有一个配置文件,如下所示:
{name1}
Settinga=1
settingb=2
settingc=3
{name2}
Settinga=1
settingb=2
settingc=3
{name3}
Settinga=1
settingb=2
settingc=3
我希望能够将{name3}下的行设置b=2更改为另一个值,如设置b=4
它将是Windows操作系统上的文件存储,因此理想情况下,它将在PowerShell或批处理命令下完成。
有人有什么想法吗?或者这是否可能?
感谢
您可以使用Get-Content
读取配置文件,并将每个名称下的部分内容存储在嵌套哈希表中,其中名称行是外部键,设置行被拆分为内部哈希表的键和值。为了维护从原始文件中找到的密钥的顺序,我们可以使用System.Collections.Specialized.OrderedDictionary
。要创建一个,只需将[ordered]
属性添加到哈希表@{}
中即可。您可以在about_Hash_Tables
了解更多信息。
我们还可以使用System.String.Split
通过=
分割行,CCD_7将使用长度来确定行是名称还是设置。长度为1是一个名称,长度为2是一个设置。
# Read lines from config file
$config = Get-Content -Path .config.txt
# Use an ordered hashtable to remember order of keys inserted
$sections = [ordered]@{}
# Keep a key which indicates the current name being added
$currentKey = $null
# Go through each line in the config file
foreach ($line in $config) {
# Split each line by '='
$items = $line.Split("=")
# If splitted items is only one value, we found a new name
# Set the new name and create an inner settings dictionary
if ($items.Length -eq 1) {
$currentKey = $line
$sections[$currentKey] = [ordered]@{}
}
# Otherwise we found a normal line
else {
# Only add the setting if the current name is not null
if ($null -ne $currentKey) {
$sections[$currentKey][$items[0]] = $items[1]
}
}
}
它将给出一个哈希表$sections
,如下所示:
Name Value
---- -----
{name1} {Settinga, settingb, settingc}
{name2} {Settinga, settingb, settingc}
{name3} {Settinga, settingb, settingc}
然后你可以设置一个值(或多个值(,如下所示:
$sections["{name3}"].settingb = 4
并使用Out-File
将更新后的哈希表写入输出文件。要迭代外部和内部哈希表,我们需要使用System.Collections.Hashtable.GetEnumerator
迭代它们的键值对。
& {
# Output each outer key first, where the names are stored
foreach ($outerKvp in $sections.GetEnumerator()) {
$outerKvp.Key
# Then output each setting and value
foreach ($innerKvp in $outerKvp.Value.GetEnumerator()) {
"$($innerKvp.Key)=$($innerKvp.Value)"
}
}
# Pipe output from script block to output file
} | Out-File -FilePath .output.txt
以上内容将foreach
循环封装在Call Operator &
内,以运行脚本块并将输出管道传输到Out-File
。您可以查看about_Pipelines
和about_Script_Blocks
以了解更多信息。
由于我提到了管道和脚本块,我们还可以使用Foreach-Object
将输入传递到管道中。从一些初步测试来看,这似乎比上述解决方案稍慢(需要用更大的输入进行进一步研究(。您可以看看Foreach对象与Foreach循环的运行时问题,了解两种方法之间的差异。
$sections.GetEnumerator() | ForEach-Object {
$_.Key
$_.Value.GetEnumerator() | ForEach-Object {
"$($_.Key)=$($_.Value)"
}
} | Out-File -FilePath .output.txt
最后是下面新创建的输出文件。
输出.txt
{name1}
Settinga=1
settingb=2
settingc=3
{name2}
Settinga=1
settingb=2
settingc=3
{name3}
Settinga=1
settingb=4
settingc=3
这表明CCD_ 18的CCD_ 17是从CCD_。