bagaimana cara menunjukkan garis yang sama (reverse diff)?

170

Saya memiliki serangkaian file teks yang ingin saya ketahui garis-garisnya secara umum daripada garis-garis yang berbeda di antara mereka. Baris perintah unix atau windows baik-baik saja.

foo:

linux-vdso.so.1 =>  (0x00007fffccffe000)
libvlc.so.2 => /usr/lib/libvlc.so.2 (0x00007f0dc4b0b000)
libvlccore.so.0 => /usr/lib/libvlccore.so.0 (0x00007f0dc483f000)
libc.so.6 => /lib/libc.so.6 (0x00007f0dc44cd000)

batang:

libkdeui.so.5 => /usr/lib/libkdeui.so.5 (0x00007f716ae22000)
libkio.so.5 => /usr/lib/libkio.so.5 (0x00007f716a96d000)
linux-vdso.so.1 =>  (0x00007fffccffe000)

Jadi, mengingat kedua file ini di atas keluaran dari utilitas yang diinginkan akan mirip file1:line_number, file2:line_number == matching text (hanya saran, saya benar-benar tidak peduli apa sintaksnya):

foo:1, bar:3 == linux-vdso.so.1 =>  (0x00007fffccffe000)

Terima kasih.

matt wilkie
sumber
@ChristopherSchultz Kesalahan saya. Baris 1 dalam contoh 1 seharusnya cocok dengan baris terakhir dalam contoh 2. Terima kasih telah menangkap kesalahannya; berubah.
matt wilkie
1
Pertanyaan serupa lainnya dengan jawaban yang baik: unix.stackexchange.com/questions/1079/…
MortezaE

Jawaban:

210

Pada * nix, Anda dapat menggunakan comm . Jawaban pertanyaannya adalah:

comm -1 -2 file1.sorted file2.sorted 
# where file1 and file2 are sorted and piped into *.sorted

Inilah penggunaan penuh dari comm:

comm [-1] [-2] [-3 ] file1 file2
-1 Suppress the output column of lines unique to file1.
-2 Suppress the output column of lines unique to file2.
-3 Suppress the output column of lines duplicated in file1 and file2. 

Perhatikan juga bahwa penting untuk menyortir file sebelum menggunakan comm, seperti yang disebutkan dalam halaman manual.

Dan Lew
sumber
3
comm [-1] [-2] [-3] file1 file2 -1 Menekan kolom output dari baris unik ke file1. -2 Menekan kolom output dari baris unik ke file2. -3 Menekan kolom output dari baris yang diduplikasi dalam file1 dan file2.
ojblass
@ojblass: Menambahkan ini ke jawabannya.
Matt J
6
Saya menemukan bahwa file-file penting disortir sebelum menggunakan comm. Mungkin tambahkan itu ke jawabannya.
matt wilkie
11
jawaban singkat untuk pertanyaan: comm -1 -2 file1 file2
greggles
6
Anda dapat menggunakan ini jika file Anda tidak diurutkan: comm -1 -2 <(sort filename1) <(sort filename2)
Kevin Wheeler
56

Menemukan jawaban ini pada pertanyaan yang terdaftar sebagai duplikat . Saya menemukan grep lebih ramah-admin daripada comm, jadi jika Anda hanya ingin set baris yang cocok (misalnya, berguna untuk membandingkan CSV) cukup gunakan

grep -F -x -f file1 file2

atau versi fgrep yang disederhanakan

fgrep -xf file1 file2

Plus, Anda dapat menggunakan file2*glob dan mencari garis yang sama dengan banyak file, bukan hanya dua.

Beberapa variasi berguna lainnya termasuk

  • -n tandai untuk menunjukkan nomor baris dari setiap baris yang cocok
  • -c untuk hanya menghitung jumlah garis yang cocok
  • -vuntuk menampilkan hanya baris dalam file2 yang berbeda (atau digunakan diff).

Menggunakan commlebih cepat, tetapi kecepatan itu datang dengan mengorbankan harus mengurutkan file Anda terlebih dahulu. Ini tidak terlalu berguna sebagai 'reverse diff'.

Ryder
sumber
terima kasih Ryder, ini bisa lebih berguna daripada kom banyak orang. Anda harus menautkan ke sumber jawaban (ada lebih dari setengah lusin yang ditautkan dalam Q di sebelah kanan; ini sedikit pekerjaan untuk ditemukan). Akan menyenangkan mengetahui bagaimana grep bekerja dengan input yang tidak diurutkan atau berbeda, dan dapat mencetak nomor baris yang sesuai.
matt wilkie
1
@ mattwilkie Saya merasa perlu untuk kembali dan mengklarifikasi penggunaan -vbendera setelah saya menyelinap sendiri. Katakanlah Anda memiliki dua file csv, file1 dan file2, dan keduanya memiliki baris yang tumpang tindih dan yang tidak tumpang tindih. Jika Anda menginginkan semua dan hanya baris yang tidak tumpang tindih, menggunakan fgrep -v file1 file2hanya akan mengembalikan baris yang tidak tumpang tindih dalam file2, dan tidak ada baris tambahan yang tidak tumpang tindih dalam file1 . Ini mungkin jelas bagi sebagian orang, tetapi lebih baik menyatakan kesalahan interpretasi yang jelas daripada risiko. Dalam kasus khusus ini, menyortir file dan menggunakan commmasih merupakan pilihan yang lebih baik.
Ryder
1
Terima kasih telah kembali dan mengklarifikasi Ryder. Perhatian ekstra dicatat dan dihargai (semua mudah untuk membiarkan hal-hal lama berlalu!). Saya telah mengalihkan jawaban yang diterima karena comm jelas merupakan pilihan komunitas, meskipun secara pribadi saya masih menggunakan ini ketika menyortir overhead yang tidak diinginkan.
matt wilkie
2
Komplikasi lain saat menggunakan grep: setiap baris kosong di file pertama akan cocok dengan setiap baris di file kedua. Pastikan file1tidak memiliki garis kosong, atau akan terlihat file-file tersebut identik.
Christopher Schultz
grep -Fxfini untukku.
loxaxs
35

Ditanyakan di sini sebelumnya: Perintah Unix untuk menemukan baris yang umum dalam dua file

Anda juga dapat mencoba dengan perl (kredit diberikan di sini )

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
ChristopheD
sumber
1
Terima kasih. Saya ingin menerima kedua jawaban, karena perl one liner adalah platform silang. Comm mendapat anggukan karena lebih sederhana.
matt wilkie
1
Sempurna. Menggunakan terminal cygwin di windows dan commtidak tersedia. Ini adalah alternatif yang sempurna.
Qix - MONICA DISEBUTKAN
3
Ini tidak peduli tentang bagaimana garis-garis itu dipesan. Ini lebih akurat daripada komunikasi.
enl8enmentnow
1
Penjelasannya ada di sini: stackoverflow.com/questions/17552789/…
Chris Koknat
17

Saya baru belajar perintah comm dari utas ini, tetapi ingin menambahkan sesuatu: jika file tidak diurutkan, dan Anda tidak ingin menyentuh file asli, Anda dapat mem-pipe outptut dari perintah sortir. Ini membiarkan file asli tetap utuh. Bekerja di bash, saya tidak bisa mengatakan tentang kerang lainnya.

comm -1 -2 <(sort file1) <(sort file2)

Ini dapat diperluas untuk membandingkan output perintah, bukan file:

comm -1 -2 <(ls /dir1 | sort) <(ls /dir2 | sort)
Greg Mueller
sumber
9

Cara termudah untuk dilakukan adalah:

awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2

File tidak perlu disortir.

Gopu
sumber
1
Ini tidak seperti sebagian besar jawaban di sini karena memungkinkan Anda merekonstruksi templat sumber. Saya memiliki dua file yang dibangun dari pembungkus yang sama, dengan teks yang berbeda disisipkan pada beberapa titik. Jawaban ini memungkinkan saya untuk memulihkan pembungkus.
Lucas Gonze
1

Sekedar informasi, saya membuat alat kecil untuk Windows melakukan hal yang sama dari "grep -F -x -f file1 file2" (Karena saya belum menemukan sesuatu yang setara dengan perintah ini pada Windows)

Ini dia: http://www.nerdzcore.com/?page=commonlines

Penggunaan adalah "CommonLines inputFile1 inputFile2 outputFile"

Kode sumber juga tersedia (GPL)

Zivilyn Bane
sumber
1

Di Windows Anda dapat menggunakan Powershell Script dengan CompareObject

compare-object -IncludeEqual -ExcludeDifferent -PassThru (get-content A.txt) (get-content B.txt)> MATCHING.txt | Out-Null #Find Matching Lines

BandingkanObjek:

  • IncludeEqual tanpa -ExcludeDifferent: Semuanya
  • ExcludeDifferent without -InclueEqual: Nothing
Shrike
sumber