Как объединить FileA.txt и FileB.txt, чтобы дать FileB.txt возможность перезаписывать с помощью сценария bash?

Возможный дубликат:
Как я могу заменить строки в текстовом файле строками из другого файла на основе совпадающих ключевых полей?

Я хочу объединить следующие файлы и хочу, чтобы содержимое FileB.txt перезаписало FileA.txt, где есть общие строки, но я не хочу полностью заменять FileA.txt на FileB.txt.

Например:

Файл А:

# 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

Файл Б:

# 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 =

В этом случае результат слияния должен быть:

# 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 =

Таким образом, все, что находится перед «=» в каждой строке, должно быть проверено и сопоставлено между FileA.txt и FileB.txt. Если что-то после «=» в FileB.txt отличается от FileA.txt, то все, что находится в FileB.txt, должно быть записано в FileA.txt.


person bramford    schedule 01.06.2012    source источник
comment
Это не то, что я хотел бы написать в bash...   -  person Ignacio Vazquez-Abrams    schedule 01.06.2012


Ответы (3)


Попробуйте эту команду sort:

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

-t=: разбить строки на поля по '=', так что сортируете по ключам

-k1,1: сортировка по первому полю. Это важно, так как дублирование (см. ниже) зависит только от указанного поля сортировки.

-u: удалить дубликаты. Если две строки имеют один и тот же ключ, сохраняется только первая.

-s: стабильная сортировка. Если две строки идентичны в зависимости от их поля сортировки, строка, которая отображается первой во входных данных, остается первой в выходных данных.

Помещая FileB.txt в список входных файлов первым, вы гарантируете, что строка из FileB.txt будет выбрана вместо строки из FileA.txt, если они имеют один и тот же ключ.

person chepner    schedule 01.06.2012
comment
Эта команда, безусловно, самая короткая и простая для понимания. - person bramford; 05.06.2012

Вот чистый способ BASH, согласованность и производительность выброшены за борт. Это то, что вы никогда не будете использовать в критическом приложении.

Если вы используете это в критическом приложении, рассмотрите возможность поиска библиотеки конфигурации. Например, в Java для этого отлично подходит класс Properties. Это работает для простых скриптов, возможно, вам придется немного изменить регулярное выражение.

Файлы свойств могут содержать более одного символа «=» в одной строке, если они правильно экранированы или заключены в кавычки. В этом скрипте это может вызвать проблемы

#!/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
person Jeffrey Vandenborne    schedule 01.06.2012

#!/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]
        }
    }
}

Запустите это так:

$ ./interfacemerge FileB.txt FileA.txt
person Dennis Williamson    schedule 01.06.2012