Salin jenis file tertentu menjaga struktur folder

108

Saya memiliki struktur folder dengan banyak file * .csv yang tersebar di folder. Sekarang saya ingin menyalin semua file * .csv ke tujuan lain dengan menjaga struktur folder.

Ini bekerja dengan melakukan:

cp --parents *.csv /target
cp --parents */*.csv" /target
cp --parents */*/*.csv /target
cp --parents */*/*/*.csv /target
...

dan seterusnya, tetapi saya ingin melakukannya dengan menggunakan satu perintah.

Wilfred Hughes
sumber

Jawaban:

126

Apakah ada alasan mengapa orang menolak menggunakan find -exec? Ini sangat berguna.

find . -name '*.csv' -exec cp --parents \{\} /target \;

Ketahui alat Anda. ;-)

msb
sumber
62
Mungkin karena ini \ {\} \;
igo
12
'{}'bekerja dengan baik
OrangeDog
3
Meskipun -execdirlebih aman daripada itu -exec, hanya mengganti satu dengan yang lain tidak mempertahankan struktur folder sebagaimana dimaksud.
Simon Shine
2
Mengapa saya mendapatkan pesan 'Menghilangkan direktori' ketika saya mencoba menyalinnya dengan perintah Anda?
Vicky Dev
4
Bisakah Anda jelaskan mengapa kawat gigi harus dilepaskan di sini?
Noumenon
46

Anda juga bisa menggunakannya rsyncuntuk ini.

$ rsync -a --prune-empty-dirs --include '*/' --include '*.csv' --exclude '*' source/ target/

Jika Anda ingin menyimpan direktori kosong dari pohon sumber, lewati --prune-empty-dirsopsi:

$ rsync -a --include '*/' --include '*.csv' --exclude '*' source/ target/

Jika Anda tidak ingin symlink, tanggal modifikasi, izin file, pemilik, dll. Dipertahankan, ganti -adengan kombinasi lain dari -rlptgoD. ;-)

Dubu
sumber
1
-madalah jalan pintas untuk --prune-emty-dirs.
Geremia
Juga, -Ropsi dapat ditambahkan untuk menyalin struktur direktori induk sumber. (lihat jawaban saya di sini.)
Geremia
-R bekerja untukku! Terima kasih
gigi2
32

Anda dapat menggunakan find dan cpio dalam mode pass through

find . -name '*.csv' | cpio -pdm  /target

Ini akan menemukan semua file .csv di direktori saat ini dan di bawah ini dan menyalinnya ke / target mempertahankan struktur direktori yang sudah di-root ..

Jika Anda menggunakan

find /path/to/files -name '*.csv' | cpio -pdm /target

itu akan menemukan semua file di dalam /path/to/filesdan di bawah dan menyalinnya ke /target/path/to/filesdan di bawah.


sumber
3
Saya mencoba semua jawaban dari atas ke bawah untuk yang satu ini, dan ini adalah satu-satunya yang bekerja pada upaya pertama
OscarRyz
21

The cpperintah memungkinkan beberapa argumen sumber:

cp **/*.csv --parents ../target

CAVEAT: Saya menggunakan bola rekursif di sini; ini adalah globstaropsi dalam Bash 4+ dan ksh, dan didukung secara default pada zsh. Gumpalan rekursif tidak cocok dengan file dan folder tersembunyi, dan beberapa implementasi mengikuti symlink sedangkan yang lain tidak .

Jika shell Anda tidak mendukung gumpalan rekursif, atau jika Anda memilih untuk tidak menggunakannya, Anda dapat melakukan hal berikut:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - ini tentu saja sangat berlebihan dan perlu mengetahui seberapa dalam struktur direktori Anda.
  • $(find . -name '*.csv')- Ini akan cocok dengan file dan folder tersembunyi. findjuga mendukung menentukan apakah symlink diikuti atau tidak, yang mungkin bermanfaat.
Kyle Strand
sumber
ini persis apa yang saya coba (gumpalan rekursif) dan ia menemukan beberapa tetapi tidak semua? sangat aneh. Saya mendapatkan hasil yang persis sama ketika menggunakan skrip copyfiles npm tetapi jika saya menggunakan perintah find ia menemukan segalanya ...
Randyaa
@Randyaa Saya perlu beberapa detail lebih lanjut tentang file mana, tepatnya, tidak ditemukan untuk membantu Anda. Anda dapat menemukan diskusi di sini dan melanjutkan di sini tentang perilaku tepat gumpalan rekursif yang bermanfaat.
Kyle Strand
1
ternyata glob rekursif tidak diaktifkan untuk beberapa alasan ... Saya belum pernah mengalami ini sebelumnya tetapi saya memperbaikinya hanya dengan eksekusi shopt -s globstarsegera sebelum perintah saya dan semuanya baik-baik saja. Terima kasih atas tindak lanjutnya!
Randyaa
--parentsadalah apa yang saya cari. terima kasih
Josh
17

Yang ini bekerja untuk saya:

find -name "*.csv" | xargs cp --parents -t /target

marko
sumber
Jawaban terbaik dengan sintaksis paling sederhana. Bekerja dengan baik dan mudah diingat. Dalam banyak kasus find [things] | xargs [do stuff]sangat kuat.
Everyday Astronaut
Sepakat. Sangat mudah dibandingkan dengan beberapa jawaban lainnya.
Tim B
1
Istirahat jika Anda memiliki spasi dalam nama file
Michele Piccolini
@MichelePiccolini Spaces dalam nama file dapat ditangani dengan find -print0dan xargs -0.
pasztorpisti
8

Dengan asumsi Anda ingin meniru struktur ini dari ./sourceke ./destination:

cd source
find . -name "*.csv" | xargs tar cvf - | (cd ../destination ; tar xfp -)

Saya siap untuk menghitung itu sebagai satu baris, cd sourcemenjadi shell builtin.

MadHatter
sumber
2
Saya tidak berpikir dia benar-benar berarti satu perintah - hanya saja tidak harus fag tentang seperti contohnya;)
tarmemiliki -Copsi untuk menghindari keharusan mengubah direktori terlebih dahulu.
Bart
8

Dari rsynchalaman manual:

-R, - Relatif

Gunakan jalur relatif. Ini berarti bahwa nama path lengkap yang ditentukan pada baris perintah dikirim ke server daripada hanya bagian terakhir dari nama file. Ini sangat berguna ketika Anda ingin mengirim beberapa direktori yang berbeda secara bersamaan. Misalnya, jika Anda menggunakan perintah ini:

rsync -av /foo/bar/baz.c remote:/tmp/

... ini akan membuat file bernama baz.c di / tmp / di mesin remote. Jika sebaliknya Anda menggunakan

rsync -avR /foo/bar/baz.c remote:/tmp/

kemudian file bernama /tmp/foo/bar/baz.c akan dibuat pada mesin jarak jauh, dengan mempertahankan path lengkapnya. Elemen path tambahan ini disebut "direktori tersirat" (yaitu direktori "foo" dan "foo / bar" pada contoh di atas).

Jadi, ini juga akan berhasil:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
Geremia
sumber