[英]Merge fileA and fileB with difficult field separator using bash/awk
与我以前的问题类似: 如何合并FileA.txt和FileB.txt,以使用bash脚本赋予FileB.txt覆盖功能?
我想合并两个配置值文件,我又有fileA和fileB。 我希望来自fileA中fileB的所有行,如果两个文件中都出现相同的配置键,我希望fileB中的值覆盖fileA中的值。
每行总是以“ config”开头,然后有一个键,最后是一个值。 很难实现的部分是,该值可以是带引号的字符串,并带有空格键以分隔多个值(请参见“网站”值)。
我有一些使用awk的经验和相当多的bash经验,但是我一辈子都找不到解决方法。 感谢所有帮助。 谢谢
的fileA:
config lanIP 10.1.1.1
config wanIP 1.1.1.1
config wanIPMask 255.255.255.255
config website "http://google.com http://yahoo.com"
FILEB:
config lanIP 192.168.1.1
config wanIP 1.1.1.1
config website "http://google.com http://yahoo.com"
config moreWebsite "http://google.com http://msn.com"
预期产量:
config lanIP 192.168.1.1
config wanIP 1.1.1.1
config wanIPMask 255.255.255.255
config website "http://google.com http://yahoo.com"
config moreWebsite "http://google.com http://msn.com"
这种一线可能会帮助:
awk '{a[$2]=$0}END{for(x in a)print a[x]}' fileA fileB
注意 :上面的行很短,但没有保持行的顺序。 (您没有提到排序标准)
测试:
kent$ head a b
==> a <==
config lanIP 10.1.1.1
config wanIP 1.1.1.1
config wanIPMask 255.255.255.255
config website "http://google.com http://yahoo.com"
==> b <==
config lanIP 192.168.1.1
config wanIP 1.1.1.1
config website "http://google.com http://yahoo.com"
config moreWebsite "http://google.com http://msn.com"
kent$ awk '{a[$2]=$0}END{for(x in a)print a[x]}' a b
config wanIP 1.1.1.1
config lanIP 192.168.1.1
config moreWebsite "http://google.com http://msn.com"
config wanIPMask 255.255.255.255
config website "http://google.com http://yahoo.com"
如果您想在问题中使用相同的顺序,请尝试以下一种方法:
awk '!($2 in a){i[NR]=$2}{a[$2]=$0}END{for(x=1;x<=NR;x++)if(x in i)print a[i[x]]}' a b
测试
kent$ awk '!($2 in a){i[NR]=$2}{a[$2]=$0}END{for(x=1;x<=NR;x++)if(x in i)print a[i[x]]}' a b
config lanIP 192.168.1.1
config wanIP 1.1.1.1
config wanIPMask 255.255.255.255
config website "http://google.com http://yahoo.com"
config moreWebsite "http://google.com http://msn.com"
如果您不介意使用Python,可以使用以下脚本来完成所需的操作。 将其转换为awk应该非常简单。 通常的想法是,您按顺序处理文件并填充字典,稍后处理的文件中的值将覆盖先前处理的文件中的值:
import sys
options = {}
for fileName in sys.argv[1:]:
with open(fileName) as f:
for line in f:
parts = line.strip().split(' ', 2)
if len(parts) == 3:
options[parts[1]] = parts[2]
for k in options:
print 'config', k, options[k]
您可以这样调用脚本:
python merge.py fileA fileB
Perl解决方案:
#!/usr/bin/perl
use warnings;
use strict;
sub get_key_value {
my $line = shift;
die "Invalid line $line" unless $line =~ /^config /;
chomp $line;
return (split / /, $line, 3)[1, 2];
}
my %result;
open my $MINOR, '<', 'fileA' or die "Cannot open fileA: $!";
while (<$MINOR>) {
my ($key, $value) = get_key_value($_);
$result{$key} = $value;
}
open my $MAJOR, '<', 'fileB' or die "Cannot open fileB: $!";
while (<$MAJOR>) {
my ($key, $value) = get_key_value($_);
delete $result{$key};
print "config $key $value\n";
}
for my $rest (keys %result) {
print "config $rest $result{$rest}\n";
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.