Secara rekursif membandingkan dua direktori dengan diff -r tanpa output pada tautan yang rusak

38

Saya menggunakan diff -r a buntuk membandingkan direktori a dan b secara rekursif . Sering terjadi bahwa meskipun ada beberapa link yang rusak (link yang rusak yang sama di kedua a dan b direktori dan menunjuk ke yang sama, non-ada target).

diff kemudian menampilkan pesan kesalahan untuk kasus-kasus tersebut dan keluar dengan kode keluar non-nol, namun saya ingin tetap diam, dan keluar dengan 0 karena direktori sama di buku saya.

Bagaimana saya bisa melakukan itu?

Marcus Junius Brutus
sumber
Apakah Anda masih ingin symlink dibandingkan (dan diidentifikasi sebagai padanan tapi rusak), atau apakah dapat diterima untuk mengabaikan semua symlink ketika melakukan diff ini?
ire_and_curses
dibandingkan dan diidentifikasi sebagai setara, saya tidak peduli jika mereka rusak. Saya hanya mencoba memverifikasi bahwa rsync saya berfungsi.
Marcus Junius Brutus

Jawaban:

24

Untuk versi 3.3 atau yang lebih baru diff, Anda harus menggunakan --no-dereferenceopsi, seperti yang dijelaskan dalam jawaban Pete Harlan .

Sayangnya, versi lama dari diff tidak mendukung pengabaian symlink :

Beberapa file bukan direktori atau file biasa: mereka adalah file yang tidak biasa seperti tautan simbolik, file khusus perangkat, pipa bernama, dan soket. Saat ini, diffmemperlakukan tautan simbolik seperti file biasa; itu memperlakukan file khusus lainnya seperti file biasa jika mereka ditentukan di tingkat atas, tetapi hanya melaporkan keberadaan mereka ketika membandingkan direktori. Ini berarti bahwa patchtidak dapat mewakili perubahan pada file tersebut. Misalnya, jika Anda mengubah file mana yang ditunjuk oleh tautan simbolik, diffmengeluarkan perbedaan antara kedua file tersebut, alih-alih mengubah ke tautan simbolik.

diffharus melaporkan perubahan ke file khusus secara khusus, dan patchharus diperluas untuk memahami ekstensi ini.

Jika yang Anda inginkan adalah memverifikasi rsync (dan mungkin memperbaiki apa yang hilang), maka Anda bisa menjalankan perintah rsync untuk kedua kalinya. Jika Anda tidak ingin melakukan itu, maka memeriksa-menjumlahkan direktori mungkin sudah cukup.

Jika Anda benar-benar ingin melakukan ini diff, maka Anda dapat menggunakan finduntuk melewati symlink, dan menjalankan diff pada setiap file secara individual. Lewati direktori Anda a dan b sebagai argumen:

#!/bin/bash
# Skip files in $1 which are symlinks
for f in `find $1/* ! -type l`
do
    # Suppress details of differences
    diff -rq $f $2/${f##*/}
done

atau sebagai one-liner:

for f in `find a/* ! -type l`;do diff -rq $f b/${f##*/};done

Ini akan mengidentifikasi file yang berbeda dalam isi, atau file yang berada di sebuah tetapi tidak dalam b .

Perhatikan bahwa:

  • karena kita melewatkan symlink sepenuhnya, ini tidak akan melihat jika nama symlink tidak ada di b . Jika Anda mengharuskan itu, Anda akan memerlukan pass menemukan kedua untuk mengidentifikasi semua symlink dan kemudian secara eksplisit memeriksa keberadaannya di b .
  • File tambahan dalam b tidak akan diidentifikasi, karena daftar dibuat dari isi a . Ini mungkin bukan masalah untuk rsyncskenario Anda .
ire_and_curses
sumber
Skrip yang diajukan tidak bekerja secara rekursif untuk direktori yang ada di direktori 'a' (jalur yang dibuat untuk 'b' menggunakan b / $ {f ## *} tidak benar).
Marcus Junius Brutus
@MarcusJuniusBrutus - Ya, Anda benar. Saya pikir solusinya adalah menghapus #, mis. for f in Temukan a / *! -tipe l ;do echo $f b/${f#*/};done. Saya tidak punya waktu untuk menguji ini sekarang. Beri tahu saya jika itu berhasil.
ire_and_curses
Ini adalah lebih baik namun masih mengacaukan filepaths dalam banyak kasus. Skrip (dengan # dihapus) tampaknya perlu dipanggil dari direktori secara langsung agar 'a' berfungsi.
Marcus Junius Brutus
Jawaban ini menjadi usang ketika menggunakan GNU diff 3.3 (lihat posting di bawah)
Bernd Gloss
Script di atas memiliki beberapa masalah, karena pertama-tama menemukan semua nama file dan mengumpankannya ke baris perintah yang diperluas. (1) Ini hanya akan berfungsi dengan koleksi kecil file sejak itu. (2) Nama file apa pun dengan karakter khusus (bahkan spasi) tidak akan diproses. (3) Selalu gunakan $(xxx)bukannya backticks. Simetri backticks membuatnya lebih mudah dibaca dan mencegah bersarang. Mengenai 1 dan 2 lihat stackoverflow.com/questions/11366184/…
Stéphane Gourichon
19

Karena versi 3.3 GNU diffmendukung tidak men-symlink, tetapi kemudian membandingkan jalur yang mereka tuju.

Instal GNU diffutils> = 3.3 dan gunakan --no-dereferenceopsi; tidak ada opsi pendek untuk itu.

Diagnostik akan diam jika sama atau:

Tautan simbolik /tmp/noderef/a/symlinkdan /tmp/noderef/b/symlinkberbeda

Philippe De Muyter
sumber
Sekarang jika itu hanya akan menunjukkan perubahan konten, seolah-olah symlink adalah file biasa ...: - /
lindes
6

Anda dapat menggunakan versi yang lebih baru dari diff

Dalam diffGNU diffutils3.3 termasuk --no-dereferenceopsi yang memungkinkan Anda untuk membandingkan sendiri symlink daripada targetnya. Ini melaporkan jika mereka berbeda, diam jika mereka setuju dan tidak peduli apakah mereka rusak.

Saya tidak tahu kapan opsi ditambahkan; itu tidak ada di 2.8.1.

Pete Harlan
sumber
Saya dapat mengonfirmasi bahwa tidak ada di diff (GNU diffutils) 3.2 juga
Penatua Geek