Comment fusionner deux blocs de deux fichiers ini?
Bonjour, j'ai deux fichiers ini qui stockent les données dans des blocs comme ci-dessous:
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
Je dois fusionner ces deux fichiers comme suit:
[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
Honnêtement, je ne sais pas depuis où commencer et quelle logique est nécessaire ou l'outil.
Certaines des choses stupides que j'ai essayées pour obtenir les directions sont:
-->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
4 Réponses :
Une solution Perl consisterait à utiliser un analyseur INI tel que Config :: Tiny pour lire chacun, fusionner la structure de données résultante et écrire un nouveau fichier. Notez que cela ne préserve pas les commentaires ni l'ordre (pour ce dernier, vous pouvez utiliser Config :: Tiny :: Ordonné , mais la fusion est plus difficile).
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');
merci pour l'aide, bien que je n'ai pas ce module installé dans le système. apprécier ton aide
Config :: Tiny est pur-perl et peut donc être fatpacked dans un script.
Vous devez bien sûr installer App :: FatPacker pour ce faire, mais le processus de base serait: installer App :: cpanminus ou le télécharger à partir de cpanmin.us ; cpanm -l local Config :: Tiny
; fatpack tree $ (env PERL5LIB = "$ PWD / local / lib / perl5" fatpack packlists-pour Config / Tiny.pm)
; fichier fatpack script.pl> script.packed.pl
En utilisant awk
, vous pouvez faire ceci:
[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 '/^$/{ 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
Détails: fort>
/ ^ $ /
correspond à toutes les lignes vides que nous ignorons simplement /^\[.*\ $/
noms d'en-tête correspondants que nous stockons dans la variable hdr
a [hdr]! = "" {...}
lorsque nous avons déjà traité hdr
une fois, nous ajoutons une nouvelle ligne et la ligne courante dans le tableau a
indexé par hdr
a
indexé par hdr
. Nous stockons également hdr
dans un autre tableau seq
indexé par incrémentation du nombre pour imprimer les données dans l'ordre END
, nous parcourons le tableau seq
et imprimons chaque bloc d'en-tête et de détails. Nous ajoutons une nouvelle ligne si nous avons plus de données à traiter. merci, pouvez-vous s'il vous plaît expliquer en haut niveau afin que je puisse suivre
Bien sûr, je vais ajouter plus de détails en réponse.
ord
est le nom d'une fonction dans certains awks et dans l'extension ordchr
gawk. Utilisez un nom différent pour la baie pour la portabilité.
Ah merci Ed. Je ne savais pas que ord
était une fonction.
Ouais, ord ()
renvoie le nombre ordinal d'un caractère. Voir gnu.org/software/gawk/manual/gawk .html # Extension-Sample-Ord .
salut Anubhava, y a-t-il un moyen d'imprimer des commentaires dans la sortie de tout le fichier ou au moins du premier fichier? J'ai essayé d'ajouter / ^ # / {print; next}
mais ça gâche toute la sortie
Désolé, je n'ai pas compris cette nouvelle exigence. Veuillez modifier la question et je verrai s'il est possible de modifier cette solution
$ 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
Cela pourrait fonctionner pour vous (GNU diff & sed):
diff -au999 file1 file2 | sed '1,3d;s/.//' >file3
Utilisé diff -u999
pour unifier file1 et fil2, puis supprimez les 3 lignes d'en-tête et le premier caractère de chaque ligne.
NB Si fichier1 et fichier2 sont identiques, vous n'obtiendrez aucune sortie et les mêmes clés seront répétées si elles ont des valeurs différentes.
Que faire si les fichiers contiennent la même clé mais avec des valeurs différentes? Qu'en est-il des lignes commentées (le cas échéant).
f2
doit écraser la clé def1
en cas de dups. Les commentaires en double sont ok, je peux vivre avec ça.Vous ne direz pas que le jour où un commentaire tentera de vous poignarder pendant que vous dormez.
mais mon exigence semble si difficile que je ne peux pas penser aux commentaires du moins pour le moment