Jak porównać dwa różne pliki linia po linii w unixie?

13

Plik 1:

123
234
345
456

Plik2:

123
234
343
758

Oczekiwany wynik: Plik 3:

TRUE
TRUE
FALSE
FALSE

więc kod powinien porównać dwa pliki i wydrukować „PRAWDA”, jeśli pasuje, w przeciwnym razie powinien wypisać „FAŁSZ” w nowym pliku. Czy ktoś mógłby podać rozwiązanie tego problemu?

Velu
źródło
10
Co się stanie, jeśli oba pliki będą nierównej długości? Z jaką częścią tego problemu masz problemy?
Kusalananda
9
Możesz rzucić okiem diff.
Panki,
2
Innym przydatnym poleceniem w takich sytuacjach jest comm. Ułatwia to wylistowanie linii, które oba pliki mają wspólne lub są unikatowe dla jednego lub drugiego.
Giacomo Alzetta
1
@GiacomoAlzetta Chodzi o commto, że wymaga posortowanego wejścia. Pomijając fakt, że przykład w pytaniu nie mieć wkład sortowane, nigdy kwestia twierdzi, że jest to rzeczywiste dane, który jest używany i nigdy nie mówi nic na temat porządkowania danych.
Kusalananda
2
Sztuczka αғsнιη nljest przydatna przy commnarzucaniu sortowania plików.
glenn jackman

Odpowiedzi:

56

Użyj diffpolecenia w następujący sposób, w bashdowolnej powłoce obsługującej <(...) zastępowanie procesów lub możesz ją emulować, jak pokazano tutaj :

diff --new-line-format='FALSE'$'\n' \
     --old-line-format='' \
     --unchanged-line-format='TRUE'$'\n' \
<(nl file1) <(nl file2)

Dane wyjściowe byłyby:

TRUE
TRUE
FALSE
FALSE

--new-line-format='FALSE'$'\n, drukuj, FALSEjeśli linie są różne, a przy --old-line-format=''wyłączonym wyjściu, jeśli linia jest inna dla pliku 1, który jest znany jako stary plik do polecenia diff (możemy je również zamienić, co oznacza, że ​​jeden z nich powinien wypisać FALSEinny, należy wyłączyć).

--unchanged-line-format='TRUE'$'\n', drukuj, TRUEjeśli linie były takie same. $'\n'składni ucieczki C-styl jest używany do drukowania nowej linii po każdym wyjściu liniowym.

αғsнιη
źródło
24

Zakładając, że pliki nie zawierają znaków tabulacji:

$ paste file1 file2 | awk -F '\t' '{ print ($1 == $2 ? "TRUE" : "FALSE") }'
TRUE
TRUE
FALSE
FALSE

Służy to pastedo utworzenia dwóch rozdzielanych tabulatorami kolumn z zawartością dwóch plików w obu kolumnach. awkPolecenie porównuje dwie kolumny na każdej linii i drukuje TRUEjeśli kolumny są takie same, a inaczej drukuje FALSE.

Kusalananda
źródło
10

Zakładając, że oba pliki mają tę samą liczbę linii:

awk '{getline f2 < "file2"; print f2 == $0 ? "TRUE" : "FALSE"}' file1

Robi to porównanie numeryczne, jeśli ciągi do porównania są liczbami, a w przeciwnym razie leksykalne. Na przykład 100i 1.0e2byłoby uważane za identyczne. Zmień, aby f2"" == $0w każdym przypadku wymusić porównanie leksykalne.

W zależności od awkimplementacji porównanie leksykalne zostanie wykonane tak, jakby przy użyciu memcmp()(porównanie bajtów do bajtów) lub tak, jakby przy użyciu strcoll()(czy oba łańcuchy sortują to samo w porządku sortowania ustawień narodowych). Może to mieć znaczenie w niektórych lokalizacjach, w których kolejność nie jest poprawnie zdefiniowana dla niektórych znaków, a nie na wszystkich cyfrach dziesiętnych, jak w twojej próbce.

Stéphane Chazelas
źródło
7

Python 3

with open('file1') as file1, open('file2') as file2:
    for line1, line2 in zip(file1, file2):
        print(line1 == line2)

Wynik:

True
True
False
False

Jeśli potrzebujesz TRUEi FALSEwielkimi literami, zamień wiersz wydruku na jeden z następujących:

print(str(line1 == line2).upper())
print('TRUE' if line1 == line2 else 'FALSE')
wjandrea
źródło
2
W Pythonie 2 wykonaj import itertoolsnajpierw, a następnie użyj itertools.izipzamiast zip. W przeciwnym razie odczyta oba pliki do pamięci, prawdopodobnie wykorzystując zbyt dużo pamięci.
pkt
4

W bash, czytanie z każdego pliku w whilepętli, porównywanie odczytanych linii i drukowanie TRUElub FALSEodpowiednio:

while IFS= read -r -u3 line1; IFS= read -r -u4 line2; do
    [[ $line1 == $line2 ]] && echo TRUE || echo FALSE
done 3<file1 4<file2

Dwa wezwania do readodczytu odpowiednio z deskryptora pliku 3 i 4. Pliki są przekierowywane na te dwa przekierowania wejściowe w pętli.

Glenn Jackman
źródło
0
Tried with awk command and it worked fine


awk 'NR==FNR{a[$1];next}{if ($1 in a){print "TRUE"} else{print "False"}}' file1 file2

wynik

TRUE
TRUE
False
False
Praveen Kumar BS
źródło