Apakah ada alat untuk mendapatkan baris dalam satu file yang tidak ada di file lain?


Jawaban:


159

Iya. Alat standar grepuntuk mencari file untuk string teks dapat digunakan untuk mengurangi semua baris dalam satu file dari yang lain.

grep -F -x -v -f fileB fileA

Ini bekerja dengan menggunakan setiap baris dalam fileB sebagai pola ( -f fileB) dan memperlakukannya sebagai string polos untuk mencocokkan (bukan regex biasa) ( -F). Anda memaksa kecocokan terjadi pada seluruh baris ( -x) dan mencetak hanya garis yang tidak cocok ( -v). Karenanya Anda mencetak baris dalam fileA yang tidak berisi data yang sama dengan baris apa pun di fileB.

Kelemahan dari solusi ini adalah tidak memperhitungkan urutan baris dan jika input Anda memiliki garis duplikat di tempat yang berbeda, Anda mungkin tidak mendapatkan apa yang Anda harapkan. Solusi untuk itu adalah dengan menggunakan alat perbandingan nyata seperti diff. Anda bisa melakukan ini dengan membuat file diff dengan nilai konteks pada 100% dari baris dalam file, kemudian menguraikannya hanya untuk baris yang akan dihapus jika mengkonversi file A ke file B. (Perhatikan perintah ini juga menghapus memformat setelah mendapat garis yang benar.)

diff -U $(wc -l < fileA) fileA fileB | sed -n 's/^-//p' > fileC

@ inderpreet99 -uArgumen huruf kecil sebenarnya mengambil parameter angka asalkan tidak diikuti oleh spasi. Keuntungan dari cara saya sebelumnya adalah bahwa ia akan bekerja dengan atau tanpa nilai, sehingga Anda dapat menggunakan sesuatu dalam rutinitas sub-perintah yang mengembalikan bukan output. Huruf besar '-U' di sisi lain membutuhkan argumen.
Caleb

hati-hati, grep -f adalah O (N ^ 2) Saya percaya: stackoverflow.com/questions/4780203/…
rogerdpack

1
yang diffpipa bekerja yang memperlakukan terima kasih.
Felipe Alvarez

Untuk menjelaskan masalah penyortiran, Anda bisa menggunakan subtitusi proses dalam perintah untuk memproses setiap file sebelum yang grepdiperlukan. Contoh:grep -F -x -v -f <(sort fileB) <(sort fileA)
Tony Cesaro

@TonyCesaro Itu akan berfungsi jika kumpulan data Anda tidak spesifik pesanan dan duplikat tidak perlu diperhitungkan. Keuntungan menggunakan diffadalah bahwa posisi dalam file diperhitungkan.
Caleb

57

Jawabannya sangat tergantung pada jenis dan format file yang Anda bandingkan.

Jika file yang Anda bandingkan adalah file teks yang diurutkan, maka alat GNU yang ditulis oleh Richard Stallman dan Davide McKenzie disebut commdapat melakukan penyaringan yang Anda cari. Itu adalah bagian dari coreutils.

Contoh

Katakanlah Anda memiliki 2 file berikut:

$ cat a
1
2
3
4
5

$ cat b
1
2
3
4
5
6

Baris dalam file byang tidak ada dalam file a:

$ comm <(sort a) <(sort b) -3
    6

1
+1 untuk disebutkan comm; sayangnya, commmemerlukan file yang diurutkan
Arcege

11
jadi urutkan mereka? comm <(sort a) <(sort b) -1 -2
Sirex

Ini adalah beberapa sintaks aneh. <()? Ini berhasil dan saya mengerti, tetapi apakah ada nama untuk keanehan ini?
mlissner

2
@mlissner <()juga dikenal sebagai proses substitusi .
miku

1
commawalnya ditulis sekitar tahun 1973 oleh seseorang di Bell Labs, bukan rms. Anda merujuk pada implementasi GNU yang datang jauh kemudian. Ada banyak implementasi berbeda dari utilitas Unix sepanjang tahun.
Stéphane Chazelas

32

dari stackoverflow ...

comm -23 file1 file2

-23 menekan garis yang ada di kedua file, atau hanya di file 2. File harus diurutkan (mereka ada dalam contoh Anda) tetapi jika tidak, pipa mereka melalui sortir terlebih dahulu ...

Lihat halaman manual di sini


Ini tidak bekerja untuk saya, untuk beberapa alasan ...
Jan

@Jan apakah file Anda diurutkan? Bagaimana Anda menyortirnya?
JJS

8

Metode grep dan comm (dengan sortir) membutuhkan waktu lama pada file besar. SiegeX dan ghostdog74 membagikan dua metode awk yang hebat untuk mengekstraksi baris yang unik ke salah satu dari dua file di Stack Overflow:

$ awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2

$ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2

2
Jika Anda melakukan ini dengan file besar, maka kendala memori memuat file besar ke dalam array asosiatif akan menjadi penghalang.
Charles Duffy

4

Jika file berukuran besar dan Anda tidak memiliki pesanan khusus untuk entri Anda, grep membutuhkan waktu terlalu lama. Alternatif cepat adalah

sort file1 > 1 
sort file2 > 2 
diff 1 2 | grep "\>" | sed -e 's/> //'

[hasil file2-file1 ke layar, pipa ke file dll]

Mengubah >ke <akan mendapatkan pengurangan yang berlawanan.rm 1 2


2

Anda juga dapat mempertimbangkan vimdiff, ini menyoroti perbedaan antara file dalam editor vim


1
Tetapi adakah cara mudah untuk secara otomatis melakukan pengurangan dalam Vimdiff?
Kazark
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.