Rsync filter: menyalin satu pola saja

128

Saya mencoba membuat direktori yang akan menampung semua dan hanya PDF saya yang dikompilasi dari LaTeX. Saya suka menyimpan setiap proyek dalam folder terpisah, semua disimpan di folder besar bernama LaTeX. Jadi saya mencoba berlari:

rsync -avn *.pdf ~/LaTeX/ ~/Output/

yang harus menemukan semua pdf ~/LaTeX/dan mentransfernya ke folder keluaran. Ini tidak berfungsi. Ini memberi tahu saya bahwa tidak ditemukan kecocokan untuk " *.pdf". Jika saya meninggalkan filter ini, perintah ini mencantumkan semua file di semua folder proyek di bawah LaTeX. Jadi ada masalah dengan filter * .pdf. Saya mencoba mengganti ~/dengan path lengkap ke direktori home saya, tetapi itu tidak berpengaruh.

Saya, menggunakan zsh. Saya mencoba melakukan hal yang sama di bash dan bahkan dengan filter yang mendaftar setiap file di setiap subdirektori ... Apa yang terjadi di sini?

Mengapa rsync tidak memahami hanya filter pdf saya?


BAIK. Jadi perbarui: Tidak, saya sedang mencoba

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/

Dan ini memberi saya seluruh daftar file. Saya kira karena semuanya cocok dengan pola pertama ...

Seamus
sumber
uh, Anda tampaknya benar ... Saya pikir jawaban saya (menggunakan **pola zsh ) harusnya bekerja.
Marcel Stimberg

Jawaban:

248

TL, DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Rsync menyalin sumber ke tujuan. Jika Anda lulus *.pdfsebagai sumber, shell memperluas ini ke daftar file dengan .pdfekstensi di direktori saat ini. Tidak ada traversal rekursif yang terjadi karena Anda tidak melewatkan direktori apa pun sebagai sumber.

Jadi Anda perlu menjalankan rsync -a ~/LaTeX/ ~/Output/, tetapi dengan filter untuk memberitahu rsync untuk menyalin .pdffile saja. Aturan filter Rsync tampak menakutkan ketika Anda membaca manual, tetapi Anda dapat membuat banyak contoh hanya dengan beberapa aturan sederhana.

  • Inklusi dan pengecualian:

    • Tidak termasuk file dengan nama atau lokasi mudah: --exclude=*~, --exclude=/some/relative/location(relatif terhadap argumen sumber, misalnya tidak termasuk ini ~/LaTeX/some/relative/location).
    • Jika Anda hanya ingin mencocokkan beberapa file atau lokasi, sertakan, sertakan setiap direktori yang mengarah ke mereka (misalnya dengan --include=*/), lalu kecualikan sisanya dengan --exclude='*'. Hal ini karena:
    • Jika Anda mengecualikan direktori, ini mengecualikan semua yang ada di bawahnya. File yang dikecualikan tidak akan dianggap sama sekali.
    • Jika Anda memasukkan direktori, ini tidak termasuk isinya secara otomatis. Dalam versi terbaru, --include='directory/***'akan melakukannya.
    • Untuk setiap file, aturan pencocokan pertama berlaku (dan apa pun yang tidak pernah cocok disertakan).
  • Pola:

    • Jika suatu pola tidak mengandung a /, itu berlaku untuk direktori nama file sans.
    • Jika suatu pola diakhiri dengan /, itu hanya berlaku untuk direktori.
    • Jika sebuah pola dimulai dengan /, itu berlaku untuk seluruh jalur dari direktori yang diteruskan sebagai argumen rsync.
    • *substring dari komponen direktori tunggal (yaitu tidak pernah cocok /); **cocok dengan semua substring jalur.
  • Jika argumen sumber berakhir dengan /, isinya disalin ( rsync -r a/ bmenciptakan b/foountuk setiap a/foo). Kalau tidak, direktori itu sendiri disalin ( rsync -r a bmembuat b/a).


Jadi di sini kita perlu memasukkan *.pdf, memasukkan direktori yang mengandungnya, dan mengecualikan yang lainnya.

rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Perhatikan bahwa ini menyalin semua direktori, bahkan yang tidak mengandung file yang cocok atau subdirektori yang mengandungnya. Ini dapat dihindari dengan --prune-empty-dirsopsi (itu bukan solusi universal karena Anda kemudian tidak dapat menyalin direktori bahkan dengan mencocokkannya secara eksplisit, tapi itu persyaratan yang langka).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/
Gilles
sumber
Berbeda dengan solusi saya (menggunakan **pola zsh ), ini menciptakan kembali struktur direktori di direktori target. Saya tidak yakin apakah ini yang diinginkan OP ...
Marcel Stimberg
Saya ingin memasukkan hanya satu direktori dan mengecualikan sisa semua direktori dalam /etc/lsyncd/lsyncd.conf.luafile. Punya ide?
Dhaduk Mitesh
@ DhadukMitesh Saya tidak terbiasa dengan lsyncd. Anda harus menanyakan ini sebagai pertanyaan baru.
Gilles
25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

Standarnya adalah untuk memasukkan semuanya, jadi Anda harus secara eksplisit mengecualikan semua setelah memasukkan file yang ingin Anda transfer. Hapus --dry-run untuk benar-benar mentransfer file.

Jika Anda memulai dengan:

--exclude '*' --include '*.pdf'

Kemudian pencocokan serakah akan mengecualikan semuanya langsung.

Jika kamu mencoba:

--include '*.pdf' --exclude '*' 

Maka hanya file pdf di folder tingkat atas yang akan ditransfer. Itu tidak akan mengikuti direktori apa pun, karena itu dikecualikan oleh '*'.

jmanning2k
sumber
2
Pada 2014-03-17 ini adalah jawaban terbaik, karena ini memecahkan pertanyaan poster asli dengan tepat . Harap beri suara! Jika Anda menambahkan --prune-empty-dirs(atau pintasan -m), Anda bahkan menyimpan banyak direktori kosong di tempat tujuan, kecuali tentu saja Anda menginginkannya sebagai pengingat atau cetak biru struktural.
porg
1
Jawaban terbaik, --include = "* /" adalah kuncinya.
Martin Konicek
Saya ingin memasukkan hanya satu direktori dan mengecualikan sisa semua direktori dalam /etc/lsyncd/lsyncd.conf.luafile. Punya ide?
Dhaduk Mitesh
15

Jika Anda menggunakan pola seperti *.pdf, shell "memperluas" pola itu, yaitu itu mengganti pola dengan semua kecocokan di direktori saat ini. Perintah yang Anda jalankan (dalam hal ini rsync) tidak mengetahui fakta bahwa Anda mencoba menggunakan pola.

Saat Anda menggunakan zsh , ada solusi mudahnya: **Pola dapat digunakan untuk mencocokkan folder secara rekursif. Coba ini:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
Marcel Stimberg
sumber
Bukankah itu akan menyalin semua pdf dari suatu tempat di dalam direktori saat ini dan semuanya dari ~ / LaTeX / ke ~ / Output?
SamB
Saya kira Anda maksud rsync -avn ~/LaTeX/**/*.pdf ~/Output, tetapi solusi dengan --includelebih scalable.
Adam Byrtek
Maaf, mengoreksi perintah yang saya salah ketik terburu-buru ... Saya setuju bahwa perintah include (dalam versi SamB) lebih baik, meskipun itu sedikit lebih rumit dan spesifik untuk rsync sementara **mungkin menjadi berguna dalam situasi lain juga.
Marcel Stimberg
1
Bash 4 telah mengadopsi fitur yang sama. Oh, dan Anda tidak perlu rsync di sini, cp akan lakukan. Pada beberapa sistem, jika ada banyak file, ada baiknya dilakukan cd ~/Latex && cp -p **/*.pdf ~/Outputuntuk menghindari kesalahan "baris perintah terlalu panjang".
Gilles
1
Perhatikan bahwa pola rsync yang digunakan dalam filter sertakan dan kecualikan juga memiliki ** yang melakukan hal yang sama. Anda dapat melarikan diri * dari cangkang lain dengan meletakkannya di tanda kutip.
Dan Pritts
13

Anda dapat menggunakan finddan daftar file perantara ( files_to_copy) untuk menyelesaikan masalah Anda. Pastikan Anda berada di direktori home Anda, lalu:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

Diuji dengan Bash.

Derek Frye
sumber
Saya pikir itu adalah solusi yang paling kuat, tetapi saya akan memilih untuk menggunakan -execopsi menemukan atau menggunakan xargs. Sesuatu seperti:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Steven D
Ya ... Saya sarankan mencari juga ... meskipun saya membayangkan rsync harus dapat melakukan ini.
gabe.
Ini adalah solusi yang rapi untuk masalah yang lebih sulit juga: mungkin saya bisa menggunakan ini untuk mengecualikan file yang kelas dokumennya standaloneatau yang tidak memiliki .texfile dengan nama yang sama, karena ini akan menjadi gambar yang disertakan dalam beberapa dokumen ...
Seamus
2
Opsi rsync --files-frommenerima pembacaan dari stdin. Ini akan berhasil find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
Juan Calero
9

Menilai dari bagian "TERMASUK / MENGECUALIKAN POLA" dari halaman manual , cara untuk melakukan ini adalah

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/

Perbedaan kritis antara ini dan jawaban kbrd adalah --include="*/"bendera, yang memberitahu rsync untuk melanjutkan dan menyalin direktori yang ditemukannya, apa pun namanya. Ini diperlukan karena rsync tidak akan muncul lagi ke dalam subdirektori kecuali telah diperintahkan untuk menyalin subdirektori itu.

Juga, perhatikan bahwa tanda kutip mencegah shell mencoba memperluas pola ke nama file relatif ke direktori saat ini, dan melakukan salah satu dari yang berikut:

  1. Berhasil dan mengacaukan filter Anda (tidak terlalu mungkin di tengah-tengah bendera seperti itu, meskipun Anda benar-benar tidak pernah tahu kapan seseorang akan membuat file bernama --include=foo.pdf...)

  2. Gagal, dan berpotensi menghasilkan kesalahan alih-alih menjalankan perintah (seperti yang Anda temukan zsh lakukan secara default).

SamB
sumber
Jadi ini hanya akan menyalin PDF dan struktur direktori, sedangkan kbrd akan menyalin file, tetapi mengabaikan struktur?
Seamus
1
Hmm. Ini sepertinya masih mencoba untuk menyalin semuanya, saya kira karena itulah yang dilakukannya tanpa filter, jadi includebarang tambahan yang sudah ada di sana tidak mengubah apa pun. Jika Anda melihat apa yang saya maksud ...
Seamus
7
Anda perlu --exclude="*"setelah --include="*.pdf", atau ini akan mentransfer segalanya.
jmanning2k
@ jmanning2k: Ah. Senang mendengarnya!
SamB
4

Bagaimana dengan ini:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/
kbyrd
sumber
Tidak, man rsyncletakkan filter setelah opsi dan sebelum sumber / tujuan. Saya mencoba ini dan itu tidak berhasil
Seamus
Cara Anda menemukan file .pdf di folder saat ini, tetapi tidak secara rekursif, seperti yang saya inginkan. ( aopsinya adalah untuk arsip dan antara lain membuat salinannya menjadi rekursif.
Seamus
1
Aduh, salahku. Saya memperbarui jawaban saya.
kbyrd
+1 karena begitu dekat, dan memberi saya petunjuk tentang bagaimana menemukan materi yang relevan di halaman manual. (Semoga saya bahkan melakukannya dengan benar. :-)
SamB
3

Berikut adalah sesuatu yang harus berfungsi tanpa menggunakan find. Perbedaan dari jawaban yang sudah diposting adalah urutan aturan filter. Aturan filter dalam perintah rsync sangat mirip dengan aturan iptable, aturan pertama yang cocok dengan file adalah yang digunakan. Dari halaman manual :

Ketika daftar file / direktori yang akan ditransfer dibuat, rsync memeriksa setiap nama yang akan ditransfer terhadap daftar pola sertakan / kecualikan pada gilirannya, dan pola pencocokan pertama ditindaklanjuti: jika itu adalah pola kecualikan, maka file tersebut adalah dilewati; jika itu adalah pola sertakan maka nama file itu tidak dilewati; jika tidak ditemukan pola yang cocok, maka nama file tidak dilewati.

Dengan demikian, Anda memerlukan perintah sebagai berikut:

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/

Perhatikan pola "**. Pdf". Menurut halaman manual :

jika polanya berisi a / (tidak termasuk trailing /) atau "**", maka itu dicocokkan dengan pathname lengkap, termasuk direktori utama mana pun. Jika polanya tidak mengandung a / atau "**", maka itu hanya cocok dengan komponen akhir dari nama file. (Ingat bahwa algoritma ini diterapkan secara rekursif sehingga "nama file lengkap" sebenarnya dapat menjadi bagian dari jalur dari direktori awal ke bawah

Dalam pengujian kecil saya, ini bekerja secara rekursif ke bawah pohon direktori dan hanya memilih pdf.

Steven D
sumber
Bagaimana tepatnya Anda menguji? Menurut pemahaman saya tentang dokumentasi dan verifikasi eksperimental saya, perintah Anda hanya akan menyalin *.pdfdi direktori tingkat atas (tetapi tidak ~/LaTeX/foo/bar.pdf).
Gilles
@Gilles Crud. Kamu benar. Saya bersumpah telah menguji ini dan ternyata berhasil, tetapi sepertinya saya tidak bisa membuatnya kembali. Dan sekarang saya benar-benar membaca halaman manual yang saya kutip, masuk akal bahwa itu tidak berfungsi. Ngomel.
Steven D
1
Yah, saya menemukan di mana tes saya salah. "Tes kecil" saya ada di direktori yang memiliki file .tex dan .pdf saya sendiri. Saya kemudian membuat subdirektori "test" dan test.pdf dan test.tex di subdir itu. Namun, saya gagal untuk memperhatikan bahwa ada test.pdf di dir level atas saya, mungkin karena beberapa percobaan LaTeX cepat yang saya lakukan.
Steven D
Saya masih tidak mengerti **. Akan menyenangkan untuk memiliki contohnya. ;)
buhtz
2

Ini adalah solusi pilihan saya:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/

The findperintah lebih mudah untuk memahami daripada include / mengecualikan aturan rsync:-)

Jika Anda hanya ingin menyalin file pdf, ubah saja .jpgke.pdf

guettli
sumber