Bagaimana saya bisa mendapatkan diff untuk hanya menampilkan baris yang ditambahkan dan dihapus? Jika diff tidak bisa melakukannya, alat apa yang bisa?

69

Bagaimana saya bisa mendapatkan diff untuk hanya menampilkan baris yang ditambahkan dan dihapus? Jika diff tidak bisa melakukannya, alat apa yang bisa?

C. Ross
sumber
2
Anda perlu lebih baik mendefinisikan apa yang Anda maksud dengan menambahkan dan menghapus. Secara khusus, dapatkah garis berubah? Jika demikian, bagaimana Anda ingin saluran yang diubah ditangani? Jika Anda melakukan pemeriksaan berorientasi garis ketat, perubahan garis identik dengan baris lama yang dihapus dan baris baru ditambahkan. Misalnya, bagaimana seharusnya menangani garis yang terbagi dua? Sebagai dua 1 baris berubah? 2 garis berubah? 1 baris dihapus dan 2 baris ditambahkan? Kecuali Anda dapat menjamin bahwa baris tidak akan pernah berubah, cukup ditambahkan dan dihapus, saya pikir ini akan gagal tanpa definisi yang lebih baik.
Christopher Cashell
Saya menemukan pertanyaan yang tidak jelas. Tetapi setidaknya satu interpretasi dari pertanyaan itu dapat dijawab dengandiff A B | grep '^[<>]'
kasperd
Anda mungkin sedang mencari comm.
Jenny D berkata Reinstate Monica
@ChristopherCashell, Dia berarti mengabaikan ketertiban; masalah yang biasanya umum. Biasanya ini dilakukan dengan terlebih dahulu menyortir segmen (garis) di setiap sisi sebelum melakukan diff khas.
Pacerier
@Pacerier, Anda yakin tentang itu? Atau apakah Anda menebak? Tidak ada tentang penyortiran atau urutan pencarian yang disebutkan atau diisyaratkan dalam pertanyaan. Seperti berdiri, pertanyaannya tidak jelas dan dapat diartikan dengan berbagai cara. Tanpa mengetahui dengan pasti apa yang dia minta, kami membuat asumsi dan menawarkan solusi yang mungkin atau mungkin tidak menyelesaikan masalah yang sebenarnya. Selain itu, komentar poster asli pada salah satu jawaban menunjukkan ini tidak terkait dengan penyortiran. Itu memang ada hubungannya dengan arti "tambah dan hapus" vs. "diubah".
Christopher Cashell

Jawaban:

82

Coba komunikasi

Cara lain untuk melihatnya:

  • Tampilkan baris yang hanya ada di file a: (yaitu apa yang dihapus dari a)

    comm -23 a b
    
  • Tampilkan baris yang hanya ada di file b: (yaitu apa yang ditambahkan ke b)

    comm -13 a b
    
  • Tampilkan baris yang hanya ada di satu file atau yang lain: (tetapi tidak keduanya)

    comm -3 a b | sed 's/^\t//'
    

(Peringatan: Jika file amemiliki baris yang dimulai dengan TAB, itu (TAB pertama) akan dihapus dari output.)

Hanya file yang diurutkan

CATATAN: Kedua file harus disortir commagar berfungsi dengan benar. Jika belum diurutkan, Anda harus mengurutkannya:

sort <a >a.sorted
sort <b >b.sorted
comm -12 a.sorted b.sorted

Jika file sangat panjang, ini mungkin cukup membebani karena memerlukan salinan tambahan dan karenanya ruang disk dua kali lebih banyak.

TomOnTime
sumber
5
hanya ingin menambahkan bahwa kedua file perlu disortir (peka huruf besar-kecil) agar solusi ini menghasilkan hasil yang benar
marmor
1
Pada kerang yang cukup modern, Anda dapat mengurutkan sesuai dengan sesuatu seperticomm -12 <(sort a) <(sort b)
Joshua Huber
14

commmungkin melakukan apa yang Anda inginkan. Dari halaman manualnya:

DESKRIPSI

Bandingkan file yang diurutkan FILE1 dan FILE2 baris demi baris.

Tanpa opsi, hasilkan output tiga kolom. Kolom satu berisi baris unik untuk FILE1, kolom dua berisi baris unik untuk FILE2, dan kolom tiga berisi baris yang umum untuk kedua file.

Kolom-kolom ini dapat ditekan dengan -1, -2dan -3masing - masing.

Contoh:

[root@dev ~]# cat a
common
shared
unique

[root@dev ~]# cat b
common
individual
shared

[root@dev ~]# comm -3 a b
    individual
unique

Dan jika Anda hanya ingin baris unik dan tidak peduli file mana yang ada di dalamnya:

[root@dev ~]# comm -3 a b | sed 's/^\t//'
individual
unique

Seperti yang dikatakan halaman manual, file harus disortir terlebih dahulu.

markdrayton
sumber
9

Untuk menampilkan penambahan dan penghapusan tanpa konteks, nomor baris, +, -, <,>! dll, Anda dapat menggunakan diff seperti ini:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

Misalnya, diberikan dua file:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

Perintah berikut akan menunjukkan baris yang dihapus dari a atau ditambahkan ke b:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

keluaran:

B-ONLY
A-ONLY

Perintah yang sedikit berbeda ini akan menampilkan baris yang dihapus dari a.txt:

diff --changed-group-format='%<' --unchanged-group-format='' a.txt b.txt 

keluaran:

A-ONLY

Akhirnya, perintah ini akan menampilkan baris yang ditambahkan ke a.txt

diff --changed-group-format='%>' --unchanged-group-format='' a.txt b.txt 

keluaran

B-ONLY
iphonedroid
sumber
2

Itulah yang dilakukan diff secara default ... Mungkin Anda perlu menambahkan beberapa flag untuk mengabaikan spasi putih?

diff -b -B

harus mengabaikan garis kosong dan jumlah spasi yang berbeda.

Scott Lundberg
sumber
1
Tidak, ini juga menunjukkan garis yang DIUBAH (garis yang memiliki karakter atau empat yang berbeda). Saya ingin garis yang hanya ada di kiri atau kanan.
C. Ross
2
Anda bisa berpendapat bahwa versi berbeda dari file yang DIUBAH masing-masing hanya ada di kiri atau kanan.
markdrayton
2
Tidak ada cara bagi diff (atau alat lain) untuk secara andal memberi tahu perubahan apa, dan apa garis yang dihapus diganti dengan garis baru.
Cian
1
Secara teknis, diff memperlakukan baris "yang diubah" seolah-olah baris asli telah dihapus dan baris baru ditambahkan ... jadi secara teknis itu menunjukkan Anda hanya menambahkan dan menghapus baris.
KFro
2

Tidak, diffsebenarnya tidak menunjukkan perbedaan antara dua file dengan cara yang mungkin orang pikirkan. Ini menghasilkan urutan perintah pengeditan untuk alat yang ingin patchdigunakan untuk mengubah satu file menjadi yang lain.

Kesulitan untuk setiap upaya melakukan apa yang Anda cari adalah bagaimana mendefinisikan apa yang merupakan garis yang telah berubah versus yang dihapus diikuti oleh yang ditambahkan. Juga apa yang harus dilakukan ketika baris ditambahkan, dihapus dan diubah berdekatan satu sama lain.

Dennis Williamson
sumber
Pikiranku persis. Berapa persentase karakter dalam suatu baris yang harus diubah untuk menganggapnya sebagai karakter baru dan bukan modifikasi dari yang asli? Secara teknis bahkan jika Anda memiliki satu karakter yang sama, Anda dapat menganggapnya sebagai "perubahan" daripada penghapusan dan penyisipan.
Kamil Kisiel
1
Sudah lama sejak saya melihat diffsumber - sumbernya, tapi sepertinya saya ingat segala macam perputaran untuk melacak di mana dua file cocok untuk tetap selaras dan saya pikir ada ambang batas untuk menyerah berdasarkan seberapa jauh jaraknya. garis adalah. Tapi saya tidak ingat ada pencocokan intra-line kecuali untuk (putih) runtuh ruang kosong atau mengabaikan case. Atau (mungkin) kata-kata yang mempengaruhi itu. Bagaimanapun, ini semua tentang patchdan "vgrep" hanya datang untuk perjalanan. Mungkin. Pada hari Selasa.
Dennis Williamson
2

Alat perbandingan visual menyatukan dua file sehingga satu segmen dengan jumlah garis yang sama tetapi konten yang berbeda akan dianggap sebagai segmen yang diubah. Baris yang sepenuhnya baru antara segmen yang cocok dianggap sebagai segmen yang ditambahkan.

Ini juga merupakan cara alat baris perintah sdiff bekerja, yang menunjukkan perbandingan dua file secara berdampingan di terminal. Garis yang diubah dipisahkan oleh | karakter. Jika garis hanya ada di file A, <digunakan sebagai karakter pemisah. Jika garis hanya ada di file B,> digunakan sebagai pemisah. Jika Anda tidak memiliki karakter <dan> dalam file, Anda dapat menggunakan ini untuk hanya menampilkan baris yang ditambahkan:

sdiff A B | grep '[<>]'
Seppo Enarvi
sumber
2

Terima kasih senarvi, solusi Anda (tidak memilih) benar-benar memberi saya PERSIS apa yang saya inginkan setelah mencari usia pada satu ton halaman.

Dengan menggunakan jawaban Anda, inilah yang saya pikirkan untuk mendapatkan daftar hal-hal yang diubah / ditambahkan / dihapus. Contoh ini menggunakan 2 versi file / etc / passwd dan mencetak nama pengguna untuk catatan yang relevan.

#!/bin/bash
sdiff passwd1 passwd2 | grep '[|]' | awk -F: '{print "changed: " $1}'
sdiff passwd1 passwd2 | grep '[<]' | awk -F: '{print "deleted: " $1}'
sdiff passwd1 passwd2 | grep '[>]' | awk -F\> '{print $2}' | awk -F: '{print "added: " $1}'
geniositas
sumber
Perhatikan bahwa karena perbedaan antara "garis telah dimodifikasi" dan "garis telah dihapus dan baris lain telah ditambahkan di bawah atau di atasnya" adalah semantik. Alat diff berbasis teks umum tidak dapat memisahkan kasus-kasus itu. Akibatnya, jawaban berbasis sdiff Anda tidak dapat diandalkan untuk semua kasus.
Mikko Rantalainen
0

Saya menemukan bentuk khusus ini sering berguna:

diff --changed-group-format='-%<+%>' --unchanged-group-format='' f g

Contoh:

printf 'a\nb\nc\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

Keluaran:

-b
-c
+B
+C
-e
-f
+E
+F

Jadi itu menunjukkan baris lama dengan -diikuti segera oleh baris baru yang sesuai dengannya +.

Jika kami memiliki penghapusan C:

printf 'a\nb\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

terlihat seperti ini:

-b
+B
+C
-e
-f
+E
+F

Formatnya didokumentasikan di man diff:

       --line-format=LFMT
              format all input lines with LFMT`

dan:

       LTYPE is 'old', 'new', or 'unchanged'.
              GTYPE is LTYPE or 'changed'.

dan:

              LFMT (only) may contain:

       %L     contents of line

       %l     contents of line, excluding any trailing newline

       [...]

Pertanyaan terkait: https://stackoverflow.com/questions/15384818/how-to-get-the-difference-only-additions-between-two-files-in-linux

Diuji di Ubuntu 18.04.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber
-1

File1:

text670_1
text067_1
text067_2

File2:

text04_1
text04_2
text05_1
text05_2
text067_1
text067_2
text1000_1

Menggunakan:

diff -y file1 file2

Ini menunjukkan dua kolom untuk file repetif.

Keluaran:

text670_1                           
                                  > text04_1
                                  > text04_2
                                  > text05_1
                                  > text05_2
text067_1                           text67_1
text067_2                           text67_2
                                  > text1000_1
Adriano
sumber