如何合并两个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
答案 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相同,则将没有输出,并且如果它们的值不同,则将重复相同的键。