Membandingkan dua file di terminal linux

168

Ada dua file yang disebut "a.txt" dan "b.txt" keduanya memiliki daftar kata. Sekarang saya ingin memeriksa kata-kata mana yang ekstra dalam "a.txt" dan tidak dalam "b.txt" .

Saya membutuhkan algoritma yang efisien karena saya perlu membandingkan dua kamus.

Ali Imran
sumber
27
diff a.txt b.txttidak cukup?
ThanksForAllTheFish
Bisakah kata-kata muncul beberapa kali di setiap file? Bisakah Anda mengurutkan file?
Basile Starynkevitch
saya hanya perlu kata-kata yang tidak ada di "b.txt" dan ada di a.txt
Ali Imran

Jawaban:

343

jika Anda telah menginstal vim, coba ini:

vimdiff file1 file2

atau

vim -d file1 file2

Anda akan menemukannya fantastis.masukkan deskripsi gambar di sini

Fengya Li
sumber
9
pasti luar biasa, bagus dalam desain dan mudah untuk mengetahui perbedaannya. Ohmygod
Zen
1
Jawaban Anda luar biasa, tetapi guru saya meminta saya untuk tidak menggunakan fungsi perpustakaan apa pun: P
Ali Imran
1
Alat yang luar biasa! Ini sangat membantu.
user1205577
1
Apa arti dari warna-warna itu?
zygimantus
1
Kode-kode berwarna berarti mereka berbeda dalam dua file. @zygimantus
Fengya Li
73

Sortir dan gunakan comm:

comm -23 <(sort a.txt) <(sort b.txt)

commmembandingkan (diurutkan) file input dan secara default menghasilkan tiga kolom: baris yang unik untuk a, baris yang unik untuk b, dan baris yang ada di keduanya. Dengan menentukan -1, -2dan / atau -3Anda dapat menekan output yang sesuai. Karena itu comm -23 a bdaftar hanya entri yang unik untuk a. Saya menggunakan <(...)sintaks untuk mengurutkan file dengan cepat, jika sudah diurutkan Anda tidak perlu ini.

Anders Johansson
sumber
Saya telah menambahkan jawaban saya sendiri hanya dengan menggunakan perintah grep, tolong beri tahu saya apakah ini lebih efisien?
Ali Imran
3
@ AliImran, commlebih efisien karena ia melakukan pekerjaan dalam sekali jalan, tanpa menyimpan seluruh file dalam memori. Karena Anda menggunakan kamus yang kemungkinan besar sudah diurutkan, Anda bahkan tidak perlu melakukannya sort. Penggunaan grep -f file1 file2di sisi lain akan memuat keseluruhan file1ke dalam memori dan membandingkan setiap baris file2dengan semua entri tersebut, yang jauh lebih efisien. Ini sebagian besar berguna untuk yang kecil, tidak disortir -f file1.
Anders Johansson
1
Terima kasih @AndersJohansson untuk berbagi perintah "comm". Memang bagus. Saya sering harus melakukan gabungan luar antara file dan ini triknya.
blispr
Perhatikan karakter baris baru ... Saya baru saja menemukan bahwa \njuga akan dimasukkan untuk melakukan perbandingan.
Bin
31

Coba sdiff( man sdiff)

sdiff -s file1 file2
mudrii
sumber
28

Anda dapat menggunakan diffalat di linux untuk membandingkan dua file. Anda dapat menggunakan --changed-kelompok format dan --unchanged-kelompok format pilihan untuk data filter diperlukan.

Tiga opsi berikut dapat digunakan untuk memilih grup yang relevan untuk setiap opsi:

  • '% <' dapatkan baris dari FILE1

  • '%>' dapatkan baris dari FILE2

  • '' (string kosong) untuk menghapus baris dari kedua file.

Misalnya: diff --changed-group-format = "% <" --unchanged-group-format = "" file1.txt file2.txt

[root@vmoracle11 tmp]# cat file1.txt 
test one
test two
test three
test four
test eight
[root@vmoracle11 tmp]# cat file2.txt 
test one
test three
test nine
[root@vmoracle11 tmp]# diff --changed-group-format='%<' --unchanged-group-format='' file1.txt file2.txt 
test two
test four
test eight
Manjula
sumber
27

Jika Anda lebih suka gaya keluaran diff git diff, Anda dapat menggunakannya dengan --no-indexflag untuk membandingkan file yang tidak ada dalam repositori git:

git diff --no-index a.txt b.txt

Dengan menggunakan beberapa file dengan sekitar 200k string nama file di masing-masing, saya membandingkan (dengan timeperintah bawaan) pendekatan ini vs beberapa jawaban lain di sini:

git diff --no-index a.txt b.txt
# ~1.2s

comm -23 <(sort a.txt) <(sort b.txt)
# ~0.2s

diff a.txt b.txt
# ~2.6s

sdiff a.txt b.txt
# ~2.7s

vimdiff a.txt b.txt
# ~3.2s

commtampaknya menjadi yang tercepat sejauh ini, sementara git diff --no-indextampaknya menjadi pendekatan tercepat untuk keluaran gaya-berbeda.


Memperbarui 2018-03-25 Anda sebenarnya dapat menghilangkan --no-indexflag kecuali jika Anda berada di dalam repositori git dan ingin membandingkan file yang tidak dilacak dalam repositori itu. Dari halaman manual :

Formulir ini untuk membandingkan dua jalur yang diberikan pada sistem file. Anda bisa menghilangkan opsi --no-index ketika menjalankan perintah di pohon yang bekerja yang dikontrol oleh Git dan setidaknya salah satu jalur menunjuk di luar pohon yang bekerja, atau ketika menjalankan perintah di luar pohon yang bekerja yang dikendalikan oleh Git.

joelostblom
sumber
4

Gunakan comm -13 (memerlukan file yang diurutkan) :

$ cat file1
one
two
three

$ cat file2
one
two
three
four

$ comm -13 <(sort file1) <(sort file2)
four
Chris Seymour
sumber
1

Ini solusi saya untuk ini:

mkdir temp
mkdir results
cp /usr/share/dict/american-english ~/temp/american-english-dictionary
cp /usr/share/dict/british-english ~/temp/british-english-dictionary
cat ~/temp/american-english-dictionary | wc -l > ~/results/count-american-english-dictionary
cat ~/temp/british-english-dictionary | wc -l > ~/results/count-british-english-dictionary
grep -Fxf ~/temp/american-english-dictionary ~/temp/british-english-dictionary > ~/results/common-english
grep -Fxvf ~/results/common-english ~/temp/american-english-dictionary > ~/results/unique-american-english
grep -Fxvf ~/results/common-english ~/temp/british-english-dictionary > ~/results/unique-british-english
Ali Imran
sumber
2
Apakah Anda mencoba salah satu solusi lain? Apakah salah satu solusi ini bermanfaat bagi Anda? Pertanyaan Anda cukup umum untuk menarik banyak pengguna, tetapi jawaban Anda lebih spesifik untuk selera saya ... Untuk kasus khusus saya sdiff -s file1 file2bermanfaat.
Metafaniel
@ Metafaniel solusi saya tidak menggunakan perintah sdiff. Ini hanya menggunakan perintah linux built in untuk menyelesaikan masalah.
Ali Imran
-1

Menggunakan awk untuk itu. File uji:

$ cat a.txt
one
two
three
four
four
$ cat b.txt
three
two
one

Awk:

$ awk '
NR==FNR {                    # process b.txt  or the first file
    seen[$0]                 # hash words to hash seen
    next                     # next word in b.txt
}                            # process a.txt  or all files after the first
!($0 in seen)' b.txt a.txt   # if word is not hashed to seen, output it

Duplikat dihasilkan:

four
four

Untuk menghindari duplikat, tambahkan setiap kata yang baru bertemu di a.txt ke seenhash:

$ awk '
NR==FNR {
    seen[$0]
    next
}
!($0 in seen) {              # if word is not hashed to seen
    seen[$0]                 # hash unseen a.txt words to seen to avoid duplicates 
    print                    # and output it
}' b.txt a.txt

Keluaran:

four

Jika daftar kata dipisahkan dengan koma, seperti:

$ cat a.txt
four,four,three,three,two,one
five,six
$ cat b.txt
one,two,three

Anda harus melakukan beberapa putaran ekstra ( forputaran):

awk -F, '                    # comma-separated input
NR==FNR {
    for(i=1;i<=NF;i++)       # loop all comma-separated fields
        seen[$i]
    next
}
{
    for(i=1;i<=NF;i++)
        if(!($i in seen)) {
             seen[$i]        # this time we buffer output (below):
             buffer=buffer (buffer==""?"":",") $i
        }
    if(buffer!="") {         # output unempty buffers after each record in a.txt
        print buffer
        buffer=""
    }
}' b.txt a.txt

Keluarkan saat ini:

four
five,six
James Brown
sumber