通过块名称合并两个ini文件

时间:2019-07-10 18:32:36

标签: python perl awk sed ini

如何合并两个ini文件的两个块?

嗨,我有两个ini文件,这些文件将数据存储在以下块中:

 -->cat f1
[default]
a1=1
b1=2
c1=3

[foo]
d=1
e1=5


 -->cat f2
[default]
a2=5
b2=6

[foo]
c2=7
d2=8
e2=9

[bar]
f2=10

我需要按如下所示合并这两个文件:

[default]
a1=1
b1=2
c1=3
a2=5
b2=6

[foo]
d=1
e1=5
c2=7
d2=8
e2=9


[bar]
f2=10

老实说,我不知道从头开始,需要什么逻辑或工具。

我试图获得指导的一些愚蠢的事情是:

awk 'NR==FNR{a[$0]=$0;next} $0 in a{print}' f1 f2
[default]

[foo]

awk -vRS='' '{$1=$1}1' f1 f2 |awk '!a[$1]++'
[default] a1=1 b1=2 c1=3
[foo] d=1 e1=5
[bar] f2=10

4 个答案:

答案 0 :(得分:2)

一种Perl解决方案是使用像Config::Tiny这样的INI解析器来读取每个,合并结果数据结构,并写出一个新文件。请注意,这不会保留注释或顺序(对于后者,您可以使用Config::Tiny::Ordered,但合并起来会更困难)。

use strict;
use warnings;
use Config::Tiny;

my $config1 = Config::Tiny->read('f1');
my $config2 = Config::Tiny->read('f2');
foreach my $category (keys %$config2) {
  my $section1 = $config1->{$category} //= {};
  my $section2 = $config2->{$category};
  @$section1{keys %$section2} = values %$section2;
}
$config1->write('new');

答案 1 :(得分:2)

使用awk,您可以这样做:

awk '/^$/{
   next
}
/^\[.*\]$/{
   hdr = $0
   next
}
a[hdr] != "" {
   a[hdr] = a[hdr] ORS $0
   next
}
{
   a[hdr] = $0
   seq[++n] = hdr
}
END {
   for (i=1; i<=n; i++)
      print seq[i] ORS a[seq[i]] (i<n ? ORS : "")
}' f1 f2

[default]
a1=1
b1=2
c1=3
a2=5
b2=6

[foo]
d=1
e1=5
c2=7
d2=8
e2=9

[bar]
f2=10

详细信息:

  • /^$/匹配我们完全忽略的所有空行
  • /^\[.*\]$/与存储在hdr变量中的标头名称匹配
  • a[hdr] != "" { ... },当我们已经处理过hdr一次之后,便在由a索引的数组hdr中添加了新行和当前行
  • 否则,我们仅将当前行存储在由a索引的数组hdr中。另外,我们将hdr存储在另一个数组seq中,该数组通过递增编号索引以按顺序打印数据
  • END块中,我们遍历seq数组并打印每个标题和详细信息块。如果我们有更多数据要处理,我们会添加一个换行符。

答案 2 :(得分:1)

$ cat tst.awk
BEGIN { RS=""; ORS="\n\n"; FS=OFS="\n" }
{ key = $1 }
NR == FNR { rec[key] = $0; next }
key in rec { $1 = rec[key]; delete rec[key] }
{ print }
END {
    for (key in rec) {
        print rec[key]
    }
}

$ awk -f tst.awk file1 file2
[default]
a1=1
b1=2
c1=3
a2=5
b2=6

[foo]
d=1
e1=5
c2=7
d2=8
e2=9

[bar]
f2=10

答案 3 :(得分:0)

这可能对您有用(GNU diff和sed):

diff -au999 file1 file2 | sed '1,3d;s/.//' >file3

使用diff -u999来统一file1和fil2,然后从每行中删除3个标题行和第一个字符。

如果file1和file2相同,则将没有输出,并且如果它们的值不同,则将重复相同的键。