Saya memiliki dua drive dengan file yang sama, tetapi struktur direktori sama sekali berbeda.
Apakah ada cara untuk 'memindahkan' semua file di sisi tujuan sehingga mereka cocok dengan struktur sisi sumber? Dengan skrip mungkin?
Misalnya, drive A memiliki:
/foo/bar/123.txt
/foo/bar/234.txt
/foo/bar/dir/567.txt
Sedangkan drive B memiliki:
/some/other/path/123.txt
/bar/doo2/wow/234.txt
/bar/doo/567.txt
File yang dimaksud sangat besar (800GB), jadi saya tidak ingin menyalinnya kembali; Saya hanya ingin menyinkronkan struktur dengan membuat direktori yang diperlukan dan memindahkan file.
Saya sedang memikirkan skrip rekursif yang akan menemukan setiap file sumber pada tujuan, kemudian memindahkannya ke direktori yang cocok, membuatnya jika perlu. Tapi - itu di luar kemampuan saya!
Solusi elegan lain diberikan di sini: /superuser/237387/any-way-to-sync-directory-structure-when-the-files-are-already-on-both-sides/238086
Jawaban:
Saya akan pergi dengan Gilles dan mengarahkan Anda ke Unison seperti yang disarankan oleh hasen j . Serentak adalah DropBox 20 tahun sebelum DropBox. Mengguncang kode solid yang digunakan banyak orang (termasuk saya) setiap hari - sangat berharga untuk dipelajari. Tetap saja,
join
perlu semua publisitas yang bisa didapatnya :)Ini hanya setengah jawaban, tetapi saya harus kembali bekerja :)
Pada dasarnya, saya ingin mendemonstrasikan
join
utilitas yang sedikit diketahui yang melakukan hal itu: bergabung dengan dua tabel pada suatu bidang.Pertama, siapkan tempat uji termasuk nama file dengan spasi:
(edit beberapa direktori dan / atau nama file dalam
new
).Sekarang, kami ingin membuat peta: hash -> nama file untuk setiap direktori dan kemudian gunakan
join
untuk mencocokkan file dengan hash yang sama. Untuk menghasilkan peta, masukkan yang berikut ini dimakemap.sh
:makemap.sh
memuntahkan file dengan garis-garis bentuk, 'hash "nama file"', jadi kami hanya bergabung di kolom pertama:Ini menghasilkan
moves.txt
yang terlihat seperti ini:Langkah selanjutnya adalah benar-benar melakukan gerakan, tetapi upaya saya macet pada mengutip ...
mv -i
danmkdir -p
harus berguna.sumber
join
sangat menarik. Terima kasih telah menyampaikannya pada saya.join
input?Ada utilitas yang disebut serempak:
http://www.cis.upenn.edu/~bcpierce/unison/
Deskripsi dari situs:
Perhatikan bahwa Unison hanya mendeteksi file yang dipindahkan saat dijalankan pertama kali jika setidaknya salah satu root berada jauh, jadi meskipun Anda menyinkronkan file lokal, gunakan
ssh://localhost/path/to/dir
sebagai salah satu root.sumber
Gunakan Unison seperti yang disarankan oleh hasen j . Saya meninggalkan jawaban ini sebagai contoh skrip yang berpotensi berguna atau untuk digunakan pada server dengan hanya utilitas dasar yang diinstal.
Saya akan menganggap bahwa nama file unik di seluruh hierarki. Saya juga akan berasumsi bahwa tidak ada nama file berisi baris baru, dan bahwa pohon direktori hanya berisi direktori dan file biasa.
Pertama mengumpulkan nama file di sisi sumber.
Kemudian pindahkan file ke tempatnya di sisi tujuan. Pertama, buat pohon file rata di sisi tujuan. Gunakan
ln
alih-alihmv
jika Anda ingin menyimpan tautan keras di hierarki lama.Jika beberapa file mungkin tidak ada di tempat tujuan, buat yang sama rata
/A.staging
dan gunakan rsync untuk menyalin data dari sumber ke tempat tujuan.Sekarang ganti nama file ke tempatnya.
Setara:
Terakhir, jika Anda peduli dengan metadata direktori, panggil rsync dengan file yang sudah ada.
Perhatikan bahwa saya belum menguji cuplikan di pos ini. Gunakan dengan risiko Anda sendiri. Silakan laporkan kesalahan dalam komentar.
sumber
Terutama jika sinkronisasi yang sedang berlangsung akan berguna, Anda bisa mencoba mencari tahu git-lampiran .
Ini relatif baru; Saya belum mencoba menggunakannya sendiri.
Saya dapat menyarankannya karena ia menghindari menyimpan salinan kedua file ... ini berarti ia harus menandai file sebagai hanya-baca ("terkunci"), seperti sistem kontrol versi non-Git tertentu.
File diidentifikasi oleh sha256sum + ekstensi file (secara default). Jadi itu harus dapat menyinkronkan dua repo dengan konten file yang identik tetapi nama file yang berbeda, tanpa harus melakukan penulisan (dan melalui jaringan bandwidth rendah, jika diinginkan). Tentu saja harus membaca semua file untuk checksum mereka.
sumber
Bagaimana dengan sesuatu yang seperti ini:
Ini mengasumsikan bahwa nama file yang ingin Anda sinkronkan adalah unik di seluruh drive: jika tidak, tidak dapat sepenuhnya otomatis (namun, Anda dapat memberikan prompt bagi pengguna untuk memilih file mana yang akan diambil jika ada lebih dari itu.)
Skrip di atas akan berfungsi dalam kasus-kasus sederhana, tetapi mungkin gagal jika
name
kebetulan mengandung simbol yang memiliki arti khusus untuk regexps. Thegrep
pada daftar file juga dapat mengambil banyak waktu jika ada banyak file. Anda dapat mempertimbangkan menerjemahkan kode ini untuk menggunakan hashtable yang akan memetakan nama file ke jalur, misalnya di Ruby.sumber
grep
garis? Apakah itu hanya menemukan path lengkap file yang cocokdstlist
?ln
itu menciptakan symlink. Anda dapat menggunakanmv
untuk memindahkan file, tetapi jangan menimpa yang sudah ada. Juga, Anda mungkin ingin membersihkan direktori kosong jika ada, setelah memindahkan file. Ya,grep
perintah itu mencari baris yang berakhir pada nama file, sehingga mengungkapkan path lengkap ke sana di drive tujuan.Dengan asumsi nama file dasar unik di pohon, itu cukup mudah:
Jika Anda ingin membersihkan direktori kosong yang lama, gunakan:
sumber
Saya juga menghadapi masalah ini. Solusi berbasis md5sum tidak bekerja untuk saya, karena saya menyinkronkan file saya ke
webdav
mount. Menghitung jumlah md5sum padawebdav
tujuan juga berarti operasi file besar.Saya membuat skrip kecil
reorg_Remote_Dir_detect_moves.sh
(di github) yang mencoba mendeteksi file yang paling banyak dipindahkan dan kemudian membuat skrip shell sementara baru dengan beberapa perintah untuk menyesuaikan direktori jarak jauh. Karena saya hanya menangani nama file, skrip bukanlah solusi yang sempurna.Untuk keamanan, beberapa file akan diabaikan: A) File dengan nama yang sama (awal yang sama) di setiap sisi, dan B) File yang hanya ada di sisi jarak jauh. Mereka akan diabaikan dan dilewati.
File yang dilewati kemudian akan ditangani oleh alat sinkronisasi pilihan Anda (misalnya
rsync, unison
, ...), yang harus Anda gunakan setelah menjalankan skrip shell sementara.Jadi mungkin skrip saya berguna untuk seseorang? Jika demikian (untuk membuatnya lebih jelas) ada tiga langkah:
reorg_Remote_Dir_detect_moves.sh
(di github)/dev/shm/REORGRemoteMoveScript.sh
=> jalankan ini untuk melakukan gerakan (akan cepat dipasangwebdav
)rsync, unison
, ...)sumber
Inilah usaha saya untuk menjawab. Sebagai peringatan, semua pengalaman skrip saya berasal dari bash, jadi jika Anda menggunakan shell yang berbeda, nama perintah atau sintaks mungkin berbeda.
Solusi ini membutuhkan pembuatan dua skrip terpisah.
Skrip pertama ini bertanggung jawab untuk benar-benar memindahkan file pada drive tujuan.
Skrip kedua membuat file peta MD5 yang digunakan oleh skrip pertama dan kemudian memanggil skrip pertama pada setiap file di drive tujuan.
Pada dasarnya, apa yang terjadi adalah dua skrip yang sama dengan array asosiatif
$md5_map_file
. Pertama, semua md5 untuk file pada drive sumber dihitung dan disimpan. Terkait dengan md5 adalah jalur relatif dari root drive. Kemudian, untuk setiap file di drive tujuan, md5 dihitung. Menggunakan md5 ini, path file itu pada drive sumber terlihat. File pada drive tujuan kemudian dipindahkan untuk mencocokkan jalur file pada drive sumber.Ada beberapa peringatan dengan skrip ini:
sumber
md5sum
sepertinya bukan hal yang harus digunakan di sini. (BTW,rsync
memiliki mode di mana ia tidak menghitung checksum.)