Làm cách nào để sử dụng lệnh 'cp' để loại trừ một thư mục cụ thể?


411

Tôi muốn sao chép tất cả các tệp trong một thư mục ngoại trừ một số tệp trong một thư mục con cụ thể. Tôi đã nhận thấy rằng lệnh 'cp' không có tùy chọn --exclude. Vì vậy, làm thế nào tôi có thể đạt được điều này?



6
tar -c | tar -x?
mvds

1
@mvds, đồng ý với bạn, sử dụng tar với '--exclude' là một ý tưởng hay.
Huang F. Lei

Câu trả lời:


704

rsync rất nhanh và dễ dàng:

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

Bạn có thể sử dụng --excludenhiều lần.

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

Lưu ý rằng thư mục thefoldertoexcludesau --excludetùy chọn có liên quan đến sourcefolder, tức là , sourcefolder/thefoldertoexclude.

Ngoài ra, bạn có thể thêm -nchạy khô để xem những gì sẽ được sao chép trước khi thực hiện thao tác thực sự và nếu mọi thứ đều ổn, hãy xóa -nkhỏi dòng lệnh.


3
Đồng ý, bạn không thể đánh bại sự đơn giản và sức mạnh của--exclude
Matthew Wilcoxson

31
thefoldertoexcludeliên quan đến sourcefolderhoặc các dir làm việc hiện tại? cảm ơn
Beebee

46
Nó liên quan đến thư mục nguồn. Điều này sẽ loại trừ nguồn thư mục / .git khỏi bị sao chép. rsync -r
orkoden

15
Có thể tôi sai nhưng tôi nghĩ rằng đó là một cách thực hành tốt để thêm "công tắc" trước "tham số". Ngoài ra, trang man của báo cáo rsync - bao gồm có thể sử dụng như với cú pháp "=" hoặc không có. Vì vậy, để làm nổi bật các hệ điều hành, tôi sẽ sử dụng rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder- dù sao thì hãy nâng cấp cho rsync thay vì tìm, vì bạn có thể dễ dàng sử dụng các đường dẫn tuyệt đối cho nguồn trong khi tìm thấy nó khó hơn khi sử dụng {}trong dst.
Xavi Montero

1
@mamun Tất nhiên, ví dụ: từ máy chủ từ xa đến máy cục bộ: $ rsync user@example.com:/var/www/mypage /var/www/mylocalpage/hoặc từ cục bộ đến từ xa$ rsync /var/www/mylocalpage/ user@example.com:/var/www/mypage
sobi3ch

84

Chà, nếu loại trừ một số mẫu tên tệp nhất định phải được thực hiện bởi mọi tiện ích tệp unix-ish (như cp, mv, rm, tar, rsync, scp, ...), sẽ xảy ra sự trùng lặp lớn về nỗ lực. Thay vào đó, những điều như vậy có thể được thực hiện như một phần của Globing , tức là bằng vỏ của bạn.

bash

man 1 bash, / Extglob .

Thí dụ:

$ shopt -s extglob
$ echo hình ảnh / *
hình ảnh / 004.bmp hình ảnh / 033.jpg hình ảnh / 1276338351183.jpg hình ảnh / 2252.png
$ echo hình ảnh /! (*. jpg)
hình ảnh / 004.bmp hình ảnh / 2252.png

Vì vậy, bạn chỉ cần đặt một mô hình bên trong !(), và nó phủ nhận trận đấu. Mô hình có thể phức tạp tùy ý, bắt đầu từ việc liệt kê các đường dẫn riêng lẻ (như Vanwaril hiển thị trong một câu trả lời khác) : !(filename1|path2|etc3), cho đến những thứ giống như regex với các ngôi sao và các lớp nhân vật. Tham khảo trang hướng dẫn để biết chi tiết.

zsh

man 1 zshexpn, / tạo tên tệp .

Bạn có thể làm setopt KSH_GLOBvà sử dụng các mẫu giống như bash. Hoặc là,

% setopt EXTENDED_GLOB
% hình ảnh phản hồi / *
hình ảnh / 004.bmp hình ảnh / 033.jpg hình ảnh / 1276338351183.jpg hình ảnh / 2252.png
% hình ảnh phản hồi / * ~ * .jpg
hình ảnh / 004.bmp hình ảnh / 2252.png

Vì vậy, x~yphù hợp với mô hình x, nhưng loại trừ mô hình y. Một lần nữa, để biết chi tiết đầy đủ tham khảo manpage.


mới!

Các vỏ có một câu trả lời đẹp hơn nhiều như thế này:

🐟 cp (chuỗi khớp -v '* .excluded.names' - srcdir / *) Destdir

Tiền thưởng pro-tip

cp *, nhấn CtrlX*và chỉ xem những gì xảy ra. Tôi hứa là không có hại


@MikhailGolubtsov có lẽ đó là vì Globing không được đệ quy và hoạt động một cấp tại một thời điểm. Chỉnh sửa ra. PS: zshmặc dù nó hoạt động .
ulidtko

3
Đẹp pro-tip! Bằng cách này bạn có thể loại bỏ các mục đơn giản một cách dễ dàng. Cảm ơn rất nhiều!
taffit

BTW, để tắt các tính năng khớp mẫu mở rộng trong Bash, hãy chạy setopt -u extglob.
Rockallite

49

Tại sao sử dụng rsynckhi bạn có thể làm:

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

Điều này giả định cấu trúc thư mục đích giống như của nguồn.


8
Tôi nghĩ rằng bạn cần -pathđối số để kiểm tra hệ thống phân cấp đường dẫn, không phải là trò chơi
James Murty

3
Và bạn cũng sẽ cần một dấu chấm phẩy ở cuối:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Matthew Wilcoxson

1
Ồ, nó sẽ không cho tôi: "Chỉnh sửa phải có ít nhất 6 ký tự"!
Matthew Wilcoxson

1
@MatthewWilcoxson Meh. Những hạn chế đó sẽ được gỡ bỏ, ngay khi bạn đạt được thêm một chút đại diện. Tôi chỉnh sửa câu trả lời cho phù hợp. Cảm ơn một lần nữa!
Linus Kleen

1
@Henning tại sao không rsync? Vì nó có thể không có trong hệ thống! trong khi find, cpluôn luôn ở vị trí của họ Hoặc bạn từ loại người, những người đã cài đặt 2gigs thứ để làm những việc đơn giản?
Reishin

37
cp -r `ls -A | grep -v "c"` $HOME/

1
Làm việc cho tôi trong Windows 10 .sh
atwellpub

Tạo một hàm shell giúp đơn giản hóa việc sử dụng cho đường dẫn nguồn tùy chỉnh và loại trừ chỉ một tệp hoặc thư mục: # $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

thất bại với các thư mục có khoảng trắng
Sérgio

27

Cách dễ nhất tôi tìm thấy, nơi bạn có thể sao chép tất cả các tệp trừ tệp và thư mục chỉ bằng cách thêm tên của chúng trong ngoặc đơn:

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/

9
Không làm việc cho tôi. Tôi nhận được-bash: !: event not found
genorama

8
shopt -s extglob (thực hiện điều này để kích hoạt! trong cp, rm và những người khác)
imkost


10

Nó liên quan đến thư mục nguồn.
Điều này sẽ loại trừ thư mục source/.gitkhỏi bị sao chép.

rsync -r --exclude '.git' source target

Sự khác biệt / cải tiến so với câu trả lời hàng đầu là gì?
giảm hoạt động

8

rsync

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

và trước tiên hãy thử với tùy chọn -n để xem những gì sẽ được sao chép


Sự khác biệt / cải tiến so với câu trả lời hàng đầu là gì?
giảm hoạt động

7

Tôi giả sử bạn đang sử dụng bash hoặc dash. Điều này sẽ làm việc?

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

Thực hiện một ls không bao gồm các tệp bạn không muốn và sử dụng đó làm đối số đầu tiên cho cp


9
Bạn có thể bỏ qua phần phụ lsvà chỉ cần làm cp !(file1|file1) dest.
Shawn Chin

Không sử dụng -laR. nó thêm chuỗi can thiệp vào cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL

5

Một tùy chọn đơn giản khác là cài đặt và sử dụng rsync có tùy chọn --exclude-dir và có thể được sử dụng cho cả tệp cục bộ và tệp từ xa.


4

rsyncthực sự là khá khó khăn phải làm nhiều bài kiểm tra để làm cho nó hoạt động.

Giả sử bạn muốn sao chép /var/www/htmlvào /var/www/devnhưng cần loại trừ /var/www/html/site/video/ thư mục có thể do kích thước của nó. Lệnh sẽ là:

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

Một số cảnh báo :

  1. Dấu gạch chéo cuối cùng /trong nguồn là cần thiết, nếu không, nó cũng sẽ sao chép thư mục nguồn chứ không phải nội dung của nó và trở thành /var/www/dev/html/xxxx, có thể không phải là điều bạn muốn.
  2. Đường --excludedẫn có liên quan đến nguồn trực tiếp. Ngay cả khi bạn đặt đường dẫn tuyệt đối đầy đủ, nó sẽ không hoạt động.

  3. -vdành cho verbose, -adành cho chế độ lưu trữ, có nghĩa là bạn muốn đệ quy và muốn bảo tồn hầu hết mọi thứ.


một giải pháp đơn giản giúp chăm sóc các ký tự đặc biệt và khoảng trắng
Sérgio

Cảm ơn đã giải thích các thông số, không giống như câu trả lời hàng đầu hiện tại!
giảm hoạt động

3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

Chỉnh sửa: quên loại trừ đường dẫn đích (nếu không nó sẽ sao chép đệ quy).


4
xem ra cho các mục thư mục có chứa không gian.
Paulo Scardine

3

Đây là một sửa đổi câu trả lời của Linus Kleen. Câu trả lời của anh ấy đã không làm việc cho tôi vì sẽ có một. được thêm vào trước đường dẫn tệp mà cp không thích (đường dẫn sẽ trông giống như nguồn / .destination / tệp).

Lệnh này đã làm việc cho tôi:

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

lệnh --parents bảo tồn cấu trúc thư mục.


2

Chỉ cần di chuyển nó tạm thời vào một thư mục ẩn (và đổi tên nó sau, nếu muốn).

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname

1
Có thể không đẹp - nhưng đây là tùy chọn duy nhất tôi tìm thấy ở đây hoạt động với cpvà vỏ POSIX tiêu chuẩn như thế nào sh.
tomekwi

1
Câu trả lời này được đánh giá thấp đáng kể. Đây là câu trả lời tương thích nhất, dễ đọc nhất và dễ hiểu. Kudos, tôi không biết tại sao tôi không nghĩ về nó.
Robert Talada

Cảm ơn @RobertTalada, câu trả lời sẽ đi được bao xa? ️🌈
lama12345

1
mv tobecopied/tobeexcluded .
cp -r tobecopied dest/
mv tobeexcluded tobecopied/

0

Tôi sử dụng vòng lặp "do while" để đọc đầu ra của lệnh find. Trong ví dụ này, tôi phù hợp (thay vì loại trừ) một số mẫu nhất định vì có số lượng mẫu phù hợp hạn chế hơn mà tôi muốn hơn là tôi không muốn. Bạn có thể đảo ngược logic bằng một -not ở phía trước các cờ -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

Tôi sử dụng ở trên để sao chép tất cả các tệp loại nhạc mới hơn trên máy chủ của mình so với các tệp trên Western Digital TV Live Hub mà tôi đã gắn tại / media / wd. Tôi sử dụng ở trên vì tôi có rất nhiều tệp DVD, mpeg, v.v. mà tôi muốn loại trừ VÀ vì lý do nào đó rsync trông giống như nó đang sao chép, nhưng sau khi tôi nhìn vào thiết bị wd, các tệp không có mặc dù không có lỗi trong rsync với lệnh này:

    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/

0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

Phần đầu tiên lstất cả các tệp nhưng ẩn các tệp cụ thể với cờ -I. Đầu ra của lsđược sử dụng làm đầu vào tiêu chuẩn cho phần thứ hai. xargsxây dựng và thực hiện lệnh cp -rf -t destdirtừ đầu vào tiêu chuẩn. cờ -rcó nghĩa là sao chép các thư mục theo cách đệ quy, -fcó nghĩa là sao chép các tệp cưỡng bức sẽ ghi đè lên các tệp trong destdir, -tchỉ định sao chép thư mục đích vào.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.