How do I merge FileA.txt and FileB.txt giving File

2019-06-06 19:55发布

Possible Duplicate:
How can I replace lines in a text file with lines from another file based on matching key fields?

I want to merge the following files and I want the contents of FileB.txt to overwrite FileA.txt where there are common lines, but I don't want to completely replace FileA.txt with FileB.txt.

For example:

File A:

# cat FileA.txt 
interface.1.type = ethernet
interface.1 = A
interface.1.ip = 192.168.1.1
interface.1.netmask = 255.255.255.0
interface.1.dhcp = false

File B:

# cat FileB.txt 
interface.1 = B
interface.1.ip = 192.168.1.1
interface.1.netmask = 
interface.1.dhcp = true
interface.1.dhcp.range = 192.168.1.1,192.168.1.15
interface.1.extraline =

In this case The merge result should be:

# cat FileA.txt
interface.1.type = ethernet
interface.1 = B
interface.1.ip = 192.168.1.1
interface.1.netmask = 
interface.1.dhcp = true
interface.1.dhcp.range = 192.168.1.1,192.168.1.15
interface.1.extraline =

So anything before the '=' on each line should be checked and matched between FileA.txt and FileB.txt. If any after the '=' on FileB.txt differs from FileA.txt then whatever is in FileB.txt should be written to FileA.txt.

4条回答
迷人小祖宗
2楼-- · 2019-06-06 20:20

Here's the pure BASH way, consistency and performance are thrown overboard. This is something you would never use in a critical application.

If you are using this in a critical application, consider looking for a configuration library. In Java for instance, the Properties class is great for this. This works for simple scripts though, you might have to change the regular expression a bit.

It's not illegal for property files to contain more than one "=" on one line if properly escaped or quoted. In this script it might cause problems

#!/bin/bash
FILEA="filea.txt"
FILEB="fileb.txt"
RESULT="filec.txt"
:> $RESULT

while read line; do
    ELEM=$(echo $line | perl -pe 's/\s*\=.*?$//gi')
    FILEBLINE=$(grep "^\s*$ELEM" $FILEB)
    if [[ -n $FILEBLINE ]]; then
        echo $FILEBLINE >>$RESULT
    else
        echo $line >>$RESULT
    fi
done < $FILEA
查看更多
淡お忘
3楼-- · 2019-06-06 20:23
{
    # print the fileA settings not in fileB
    awk -F= 'NR==FNR {lhs[$1]; next} !($1 in lhs)' fileB.txt fileA.txt

    # then print all of fileB
    cat fileB.txt

    # then write to a new file and overwrite fileA
} > newfile && mv newfile fileA.txt
查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-06-06 20:44
#!/usr/bin/awk -f
BEGIN {
    FS = " = ?"; OFS = " = "
}

NR == FNR {
    attrib[$1] = $2
    printed[$1] = 0
    next
}

(! ($1 in attrib)) {
    print
}

$1 in attrib && $2 != attrib[$1] {
    print $1, attrib[$1]
    printed[$1] = 1
}

END {
    for (i in printed) {
        if (! printed[i]) {
            print i, attrib[i]
        }
    }
}

Run it like this:

$ ./interfacemerge FileB.txt FileA.txt
查看更多
叛逆
5楼-- · 2019-06-06 20:45

Try this sort command:

sort -t= -k1,1 -us FileB.txt FileA.txt

-t=: split the lines into fields on the '=', so you are sorting on the keys

-k1,1: sort on the first field. This is important, as duplication (see below) depends only on the specified sort field.

-u: eliminate duplicates. If two lines have the same key, only the first is kept.

-s: stable sort. If two lines are identical based on their sort field, the line that is seen first in the input remains first in the output.

By putting FileB.txt in the list of input files first, you ensure that the line from FileB.txt is chosen over the line from FileA.txt if they share the same key.

查看更多
登录 后发表回答