объединить два INI-файла по имени блока - PullRequest
1 голос
/ 10 июля 2019

Как объединить два блока из двух файлов 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 ]

2 голосов
/ 10 июля 2019

Используя 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 голосов
/ 10 июля 2019

Решением Perl было бы использовать синтаксический анализатор INI, такой как Config :: Tiny , чтобы прочитать каждый, объединить результирующую структуру данных и записать новый файл. Обратите внимание, что это не сохраняет комментарии или порядок (для последнего вы можете использовать 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 голос
/ 10 июля 2019
$ 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
0 голосов
/ 11 июля 2019

Это может сработать для вас (GNU diff & sed):

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

Использовано diff -u999 для объединения файлов1 и fil2, затем удалить 3 строки заголовка и первый символ из каждой строки.

NB. Если file1 и file2 одинаковы, вы не получите никакого вывода, и одни и те же ключи будут повторяться, если они имеют разные значения.

...