Bagaimana cara menggunakan perintah 'cp' untuk mengecualikan direktori tertentu?

411

Saya ingin menyalin semua file dalam direktori kecuali beberapa file dalam sub-direktori tertentu. Saya perhatikan bahwa perintah 'cp' tidak memiliki opsi --exclude. Jadi, bagaimana saya bisa mencapai ini?

David Liu
sumber
18
rsync?
ajreal
6
tar -c | tar -x?
mvds
1
@ mvds, setuju dengan Anda, menggunakan tar dengan '--exclude' adalah ide yang bagus.
Huang F. Lei

Jawaban:

704

rsync cepat dan mudah:

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude

Anda dapat menggunakan --excludebeberapa kali.

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude --exclude anotherfoldertoexclude

Perhatikan bahwa opsi dir thefoldertoexcludesetelah --excluderelatif terhadap sourcefolder, yaitu sourcefolder/thefoldertoexclude,.

Anda juga dapat menambahkan -nuntuk menjalankan kering untuk melihat apa yang akan disalin sebelum melakukan operasi nyata, dan jika semuanya ok, hapus -ndari baris perintah.

gulungan
sumber
3
Setuju, Anda tidak bisa mengalahkan kesederhanaan dan kekuatan--exclude
Matthew Wilcoxson
31
adalah thefoldertoexcluderelatif ke sourcefolderatau direktori kerja saat ini? terima kasih
Beebee
46
Ini relatif ke folder sumber. Ini akan mengecualikan sumber folder / .git agar tidak disalin. rsync -r --exclude target sumber '.git'
orkoden
15
Mungkin saya salah, tetapi saya pikir ini praktik yang baik untuk menambahkan "switch" sebelum "parameter". Juga halaman manual laporan rsync --exclude dapat digunakan seperti dengan sintaks "=" atau tanpa. Jadi untuk standarisasi di seluruh sistem operasi, saya akan menggunakan rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder- tetap upvote untuk rsync daripada menemukan, karena Anda dapat dengan mudah menggunakan jalur absolut untuk sumber sementara dalam menemukan itu lebih sulit karena menggunakan {}di dst.
Xavi Montero
1
@mamun Tentu saja misalnya dari server jarak jauh ke mesin lokal: $ rsync [email protected]:/var/www/mypage /var/www/mylocalpage/atau dari lokal ke jarak jauh$ rsync /var/www/mylocalpage/ [email protected]:/var/www/mypage
sobi3ch
84

Nah, jika pengecualian pola nama file tertentu harus dilakukan oleh setiap utilitas file unix-ish (seperti cp, mv, rm, tar, rsync, scp, ...), duplikasi usaha yang sangat besar akan terjadi. Sebaliknya, hal-hal seperti itu dapat dilakukan sebagai bagian dari globbing , yaitu dengan shell Anda.

pesta

man 1 bash, / extglob .

Contoh:

$ shopt -s extglob
$ echo images / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
$ echo images /! (*. jpg)
images / 004.bmp images / 2252.png

Jadi Anda hanya memasukkan pola di dalamnya !(), dan meniadakan pertandingan. Polanya bisa rumit secara arbitrer, mulai dari penghitungan jalur individu (seperti yang ditunjukkan Vanwaril dalam jawaban lain):, !(filename1|path2|etc3)hingga hal-hal yang mirip dengan regex dengan bintang dan kelas karakter. Lihat halaman manual untuk detailnya.

zsh

man 1 zshexpn, / nama file generasi .

Anda dapat melakukan setopt KSH_GLOBdan menggunakan pola bash-like. Atau,

% setopt EXTENDED_GLOB
% Gema gambar / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
% echo images / * ~ * .jpg
images / 004.bmp images / 2252.png

Jadi x~ycocok dengan pola x, tetapi tidak termasuk pola y. Sekali lagi, untuk detail selengkapnya, lihat halaman manual.


ikan baru!

The ikan shell memiliki banyak jawaban cantik ini:

🐟 cp (string match -v '* .excluded.names' - srcdir / *) destdir

Bonus pro-tip

Ketik cp *, tekan CtrlX*dan lihat apa yang terjadi. itu tidak berbahaya, aku janji

ulidtko
sumber
@MikhailGolubtsov mungkin itu karena globbing tidak rekursif dan bekerja satu tingkat pada satu waktu. Diedit. PS: bekerja di dalamnya zsh.
ulidtko
3
Pro-tip bagus! Dengan cara ini Anda dapat menghapus satu item dengan mudah. Terima kasih banyak!
taffit
BTW, untuk mematikan fitur pencocokan pola yang diperluas di Bash, jalankan setopt -u extglob.
Rockallite
49

Mengapa menggunakan rsyncketika Anda bisa melakukan:

find . -type f -not -iname '*/not-from-here/*' -exec cp '{}' '/dest/{}' ';'

Ini mengasumsikan struktur direktori target sama dengan sumbernya.

Linus Kleen
sumber
8
Saya pikir Anda perlu -pathargumen untuk menguji hierarki jalur, bukan -nama
James Murty
3
Dan Anda juga akan memerlukan titik koma di akhir:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Matthew Wilcoxson
1
Wow, tidak akan membiarkan saya: "Editan harus setidaknya 6 karakter"!
Matthew Wilcoxson
1
@MatthewWilcoxson Meh. Batasan-batasan itu akan dicabut, segera setelah Anda memperoleh lebih banyak perwakilan. Saya mengedit jawabannya. Terima kasih lagi!
Linus Kleen
1
@ Kenapa tidak rsync? Karena mungkin tidak ada dalam sistem! sementara find, cpselalu ada di tempat mereka. Atau Anda dari jenis cowok, yang memasang 2 gram barang untuk melakukan hal-hal sederhana?
Reishin
37
cp -r `ls -A | grep -v "c"` $HOME/
anggur kumar
sumber
1
Bekerja untuk saya di Windows 10 .sh
atwellpub
Membuat fungsi shell yang menyederhanakan penggunaan untuk jalur sumber khusus dan mengecualikan hanya satu file atau direktori: # $1 = source path # $2 = destination path # $3 = filter copy_from_source_to_destination_except_filter() { cp -r $(ls -A $1 | grep -v -w $3 | awk -v path=$1 '{printf "%s/%s ", path, $1}') $2 }
ElectRocnic
gagal dengan direktori dengan spasi
Sérgio
27

Cara termudah yang saya temukan, di mana Anda dapat menyalin semua file tidak termasuk file dan folder hanya dengan menambahkan nama mereka di dalam tanda kurung:

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/
aman
sumber
9
Tidak bekerja untuk saya. Saya mendapatkan-bash: !: event not found
geneorama
8
shopt -s extglob (jalankan ini untuk mengaktifkan! di cp, rm dan lainnya)
imkost
13

Memperluas komentar mvds , ini bekerja untuk saya

cd dotfiles
tar -c --exclude .git --exclude README . | tar -x -C ~/dotfiles2
Steven Penny
sumber
10

Ini relatif terhadap direktori sumber.
Ini akan mengecualikan direktori source/.gitdari disalin.

rsync -r --exclude '.git' source target
Niyaz Ahmed Qureshi
sumber
Apa perbedaan / peningkatan dibandingkan dengan jawaban teratas?
Mengurangi aktivitas
8

rsync

rsync -r --verbose --exclude 'exclude_pattern' ./* /to/where/

dan pertama coba dengan opsi -n untuk melihat apa yang akan disalin

dzon
sumber
Apa perbedaan / peningkatan dibandingkan dengan jawaban teratas?
Mengurangi aktivitas
7

Saya menganggap Anda menggunakan bash atau dash. Apakah ini akan berhasil?

shopt -s extglob  # sets extended pattern matching options in the bash shell
cp $(ls -laR !(subdir/file1|file2|subdir2/file3)) destination

Melakukan ls mengecualikan file yang tidak Anda inginkan, dan menggunakannya sebagai argumen pertama untuk cp

Vanwaril
sumber
9
Anda dapat melewati ekstra lsdan cukup lakukan cp !(file1|file1) dest.
Shawn Chin
Jangan gunakan -laR. itu menambahkan string yang mengganggu cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL
5

Opsi lain yang lebih sederhana adalah menginstal dan menggunakan rsync yang memiliki opsi --exclude-dir, dan dapat digunakan untuk file lokal dan jarak jauh.

ehudokai
sumber
4

rsyncsebenarnya cukup rumit. harus melakukan beberapa tes untuk membuatnya berfungsi.

Katakanlah Anda ingin menyalin /var/www/htmlke /var/www/devtapi perlu mengecualikan /var/www/html/site/video/ direktori mungkin karena ukurannya. Perintahnya adalah:

rsync -av --exclude 'sites/video' /var/www/html/ /var/www/dev

Beberapa peringatan :

  1. Slash terakhir /pada sumber diperlukan, jika tidak, salin juga akan menyalin direktori sumber daripada isinya dan menjadi /var/www/dev/html/xxxx, yang mungkin bukan yang Anda inginkan.
  2. The para --excludepath adalah relatif ke sumber langsung. Bahkan jika Anda meletakkan jalur absolut penuh, itu tidak akan berhasil.

  3. -vadalah untuk verbose, -aadalah untuk mode arsip yang berarti Anda ingin rekursi dan ingin mempertahankan hampir semuanya.

LeOn - Han Li
sumber
solusi sederhana yang menangani karakter khusus dan ruang putih
Sérgio
Terima kasih telah menjelaskan parameter, tidak seperti jawaban teratas saat ini!
Mengurangi aktivitas
3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

Sunting: lupa untuk mengecualikan jalur target juga (kalau tidak itu akan menyalin secara rekursif).

sudo kerja
sumber
4
perhatikan entri direktori yang berisi spasi.
Paulo Scardine
3

Ini adalah modifikasi dari jawaban Linus Kleen. Jawabannya tidak berhasil untuk saya karena akan ada. ditambahkan di depan path file yang tidak disukai cp (path akan terlihat seperti source / .destination / file).

Perintah ini bekerja untuk saya:

find . -type f -not -path '*/exlude-path/*' -exec cp --parents '{}' '/destination/' \;

perintah --parents menjaga struktur direktori.

Milan Simek
sumber
2
mv tobecopied/tobeexcluded .
cp -r tobecopied dest/
mv tobeexcluded tobecopied/
John Smith
sumber
2

Hanya memindahkannya sementara ke direktori tersembunyi (dan ganti namanya setelah, jika diinginkan).

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname
lama12345
sumber
1
Tidak cantik mungkin - tetapi ini adalah satu-satunya pilihan yang saya temukan di sini yang bekerja dengan cpdan shell POSIX standar seperti sh.
tomekwi
1
Jawaban ini secara dramatis diremehkan. Ini adalah jawaban yang paling kompatibel, paling mudah dibaca dan mudah dipahami. Kudos, saya tidak tahu mengapa saya tidak memikirkannya.
Robert Talada
Terima kasih @RobertTalada, seberapa jauh jawabannya dari sekarang? ️‍🌈
lama12345
0

Saya menggunakan loop "do while" untuk membaca output dari perintah find. Dalam contoh ini, saya mencocokkan (daripada mengecualikan) pola tertentu karena ada jumlah pencocokan pola yang lebih terbatas yang saya inginkan daripada yang tidak saya inginkan. Anda bisa membalikkan logika dengan -tidak di depan flag -iname:

    find . -type f -iname "*.flac" -o -print0 -iname "*.mp3" -print0 -o -iname "*.wav" -print0 -o -iname "*.aac" -print0 -o -iname "*.wma" -print0 | while read -d $'\0' file; do cp -ruv "$file" "/media/wd/network_sync/music/$file"; done

Saya menggunakan hal di atas untuk menyalin semua file jenis musik yang lebih baru di server saya daripada file di Western Digital TV Live Hub yang telah saya pasang di / media / wd. Saya menggunakan hal di atas karena saya memiliki banyak file DVD, mpegs, dll. Saya ingin mengecualikan DAN karena untuk beberapa alasan rsync sepertinya sedang menyalin, tetapi setelah saya melihat perangkat wd, file tidak ada walaupun tidak ada kesalahan selama rsync dengan perintah ini:

    rsync -av --progress --exclude=*.VOB --exclude=*.avi --exclude=*.mkv --exclude=*.ts --exclude=*.mpg --exclude=*.iso --exclude=*ar --exclude=*.vob --exclude=*.BUP --exclude=*.cdi --exclude=*.ISO --exclude=*.shn --exclude=*.MPG --exclude=*.AVI --exclude=*.DAT --exclude=*.img --exclude=*.nrg --exclude=*.cdr --exclude=*.bin --exclude=*.MOV --exclude=*.goutputs* --exclude=*.flv --exclude=*.mov --exclude=*.m2ts --exclude=*.cdg --exclude=*.IFO --exclude=*.asf --exclude=*.ite /media/2TB\ Data/data/music/* /media/wd/network_sync/music/
pengguna3610268
sumber
0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

Bagian pertama lssemua file tetapi menyembunyikan file tertentu dengan flag -I. Output dari lsdigunakan sebagai input standar untuk bagian kedua. xargsmembangun dan menjalankan perintah cp -rf -t destdirdari input standar. bendera -rberarti menyalin direktori secara rekursif, -fberarti menyalin file secara paksa yang akan menimpa file dalam destdir, -tmenentukan salinan direktori tujuan.

LouisXW
sumber
0

cp -r ls -A | grep -v "Excluded_File_or_folder"../$target_location -v

Shashwot Risal
sumber