3

类似于我的旧问题: 如何合并 FileA.txt 和 FileB.txt,使用 bash 脚本赋予 FileB.txt 覆盖能力?

我想合并两个配置值文件,我又有fileA和fileB。我想要fileA中fileB中的所有行,如果两个文件中出现相同的配置键,我希望fileB中的值覆盖fileA中的值。

每行总是以'config'开头,然后是一个键,最后是一个值。使它变得困难的部分是该值可以是带有空格的带引号的字符串以分隔多个值(请参阅“网站”值)。

我有一些使用 awk 的经验和相当多的 bash 经验,但我一辈子都想不出办法来做到这一点。感谢所有帮助。谢谢

文件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"

预期输出:

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"
4

3 回答 3

5

这个单线可能会有所帮助:

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"
于 2012-11-14T09:40:17.767 回答
0

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";
}
于 2012-11-14T09:39:47.420 回答
0

如果您不介意使用 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
于 2012-11-14T09:35:59.690 回答