linux menggabungkan folder: rsync?

13

Saya punya dua salinan folder

src/
dest/

Saya ingin menggabungkan mereka, melakukan hal berikut:

Jika file hanya di src, saya ingin dipindahkandest

Jika file hanya di dest, saya ingin mengabaikan IE yang ditinggalkan sendirian.

Jika file berada di keduanya dan memiliki konten yang identik (ukuran dan tanggal yang sama), hapus darisrc

Jika file ada di keduanya dan tidak memiliki konten yang identik, tinggalkan srcbegitu sehingga saya dapat menggabungkannya secara manual.

Hanya sejumlah kecil file (antara 0% dan 5% dari total file) yang termasuk dalam kategori terakhir ini, tetapi saya tidak tahu bagaimana memisahkan keduanya dan sama dari keduanya, tetapi berbeda.

Saya sudah mencoba mencari cara melakukan ini dengan rsynctetapi tidak berhasil sejauh ini.

David Oneill
sumber

Jawaban:

17

Saya hanya melakukan pengujian fungsionalitas terbatas, jadi harap berhati-hati dengan perintah ini (--dry-run):

rsync -avPr --ignore-existing --remove-source-files src/ dest

Harap perhatikan trailing / karena ini akan muncul kembali ke src daripada menyalin src itu sendiri, ini harus mempertahankan jalur yang ada.

Dengan menggunakan flag --ignore-existing dalam kombinasi dengan flag --remove-source-files Anda hanya akan menghapus file dari src yang disinkronkan dari src ke dest, yaitu file yang sebelumnya tidak ada di dest saja.

Untuk menghapus file yang tidak disinkronkan, yaitu file yang sudah ada di dest / seperti di src /, Anda dapat menggunakan:

for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done

atau

find src -type f -exec bash -c 'cmp -s "$0" "${0/#src/dest}" && rm "$0"' {} \;

jika nama file dapat berisi spasi putih / baris baru / ... Mengenai komentar Gilles tentang karakter khusus, itu pasti sesuatu yang harus diperhatikan dan ada banyak solusi, yang paling sederhana adalah dengan mengirimkan -i ke rm yang akan meminta sebelum semua penghapusan. Asalkan src /, atau jalur induknya, disediakan untuk menemukan, bagaimanapun, jalur yang sepenuhnya memenuhi syarat harus mengakibatkan semua nama file ditangani dengan benar oleh perintah diff dan rm tanpa mengutip.

Tok
sumber
koreksi: perintah itu tidak akan menghapus file dari src jika salinan identik sudah ada di dest
Tok
Ya :(. Itulah bagian yang sulit bagi saya untuk mencari tahu.
David Oneill
2
Nah, kabar baiknya adalah bahwa Anda dapat menyelesaikannya secara mandiri tanpa banyak kesulitan: for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done(Anda dapat melewati || echo $filejika Anda suka, itu sudah termasuk untuk kelengkapan)
Tok
Nifty: itulah yang saya butuhkan. Edit itu ke dalam jawaban Anda, dan saya akan menerimanya!
David Oneill
@ Tok: Perintah Anda akan mencekik nama file yang berisi karakter khusus (spasi \?*[,, inisial -). Anda perlu menggunakan tanda kutip ganda di sekitar substitusi variabel , beralih --ke utilitas sebelum nama file, gunakan find … -exec …bukannya parsing output find. Dengan rmperintah dalam campuran, ini adalah resep untuk bencana.
Gilles 'SO- stop being evil'
6

serentak adalah alat yang Anda cari. Coba serempak-gtk jika Anda lebih suka gui. Tapi saya tidak berpikir itu akan menghapus file yang serupa: serempak mencoba untuk memiliki kedua direktori yang sama. Namun demikian itu akan dengan mudah 1) mengidentifikasi file mana yang akan disalin; 2) mana yang perlu digabung secara manual.

simonp
sumber
Itu tidak melakukan persis apa yang diminta OP, tapi sepertinya itu mencapai tujuan akhir OP. +1
Ryan C. Thompson
+1 Sedihnya, server tempat saya menjalankan ini belum diinstal secara bersamaan, saya juga tidak memiliki izin untuk menginstalnya. Tapi ini mungkin jawaban yang bagus untuk orang lain.
David Oneill
1
Anda dapat mengunduh secara bersamaan yang dapat dieksekusi dari seas.upenn.edu/~bcpierce/unison//download/… . Instal di suatu tempat di direktori rumah Anda, itu hanya satu file.
Bersenang
2

Skrip berikut harus melakukan hal-hal yang wajar. Ini memindahkan file dari sumber ke tujuan, tidak pernah menimpa file dan membuat direktori yang diperlukan. File sumber yang memiliki file berbeda yang sesuai di tujuan dibiarkan sendiri, seperti juga file yang bukan file atau direktori biasa (mis. Tautan simbolik). File-file yang tersisa di sumber adalah mereka yang ada konflik. Hati-hati, saya belum mengujinya sama sekali.

cd src
find . -exec sh -c '
    set -- "/path/to/dest/$0"
    if [ -d "$0" ]; then #  the source is a directory 
      if ! [ -e "$1" ]; then
        mv -- "$0" "$1"  # move whole directory in one go
      fi
    elif ! [ -e "$0" ]; then  # the source doesn't exist after all
      :  # might happen if a whole directory was moved
    elif ! [ -e "$1" ]; then  # the destination doesn't exist
      mv -- "$0" "$1"
    elif [ -f "$1" ] && cmp -s -- "$0" "$1"; then  # identical files
      rm -- "$0"
    fi
  ' {} \;

Pendekatan lain adalah dengan melakukan union mount satu direktori di atas yang lain, misalnya dengan funionfs atau unionfs-fuse .

Gilles 'SANGAT berhenti menjadi jahat'
sumber