Jak użyć polecenia „cp”, aby wykluczyć określony katalog?

410

Chcę skopiować wszystkie pliki w katalogu oprócz niektórych plików w określonym podkatalogu. Zauważyłem, że polecenie „cp” nie ma opcji --exclude. Jak mogę to osiągnąć?

David Liu
źródło
18
rsync?
ajreal
6
tar -c | tar -x?
mvds
1
@mvds, zgódź się z tobą, dobrym pomysłem jest użycie tar z '--exclude'.
Huang F. Lei

Odpowiedzi:

702

rsync jest szybki i łatwy:

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

Możesz użyć --excludewiele razy.

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

Zauważ, że opcja katalog thefoldertoexcludepo --excludejest względna w stosunku do sourcefolder, tj sourcefolder/thefoldertoexclude.

Możesz również dodać -ndo trybu próbnego, aby zobaczyć, co zostanie skopiowane przed wykonaniem prawdziwej operacji, a jeśli wszystko jest w porządku, usuń -nz wiersza polecenia.

motek
źródło
3
Zgadzam się, że nie można pobić prostoty i siły--exclude
Matthew Wilcoxson
31
jest thefoldertoexcludewzględny sourcefolderlub aktualny działający reż? dzięki
Beebee,
46
Jest względny do folderu źródłowego. Spowoduje to wykluczenie kopiowania folderu source / .git. rsync -r --exclude '.git' źródło target
orkoden
15
Może się mylę, ale myślę, że dobrą praktyką jest dodawanie „przełączników” przed „parametrami”. Również strona man raportów rsync - wyklucz użyteczne jak ze składnią "=" lub bez. Tak więc, aby ustandaryzować się w różnych systemach operacyjnych, rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolderużyłbym - w każdym razie upvote dla rsync zamiast find, ponieważ możesz łatwo użyć bezwzględnych ścieżek do źródła, podczas gdy w find jest trudniejsze, ponieważ używa {}dst.
Xavi Montero,
1
@mamun Oczywiście np. ze zdalnego serwera na komputer lokalny: $ rsync [email protected]:/var/www/mypage /var/www/mylocalpage/lub z lokalnego na zdalny$ rsync /var/www/mylocalpage/ [email protected]:/var/www/mypage
sobi3ch
84

Cóż, gdyby wykluczenie pewnych wzorców nazw plików musiało być wykonane przez każde narzędzie uniksowe (np. Cp, mv, rm, tar, rsync, scp, ...), nastąpiłoby ogromne powielanie wysiłku. Zamiast tego, takie rzeczy można zrobić w ramach globowania , tj. Za pomocą powłoki.

grzmotnąć

man 1 bash, / extglob .

Przykład:

$ 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

Więc po prostu umieść wzór w środku !(), a to neguje dopasowanie. Wzorzec może być dowolnie złożony, zaczynając od wyliczenia poszczególnych ścieżek (jak pokazuje Vanwaril w innej odpowiedzi): od wyrażeń !(filename1|path2|etc3)regularnych z gwiazdami i klasami postaci. Szczegółowe informacje można znaleźć na stronie podręcznika.

zsh

man 1 zshexpn, / generowanie nazw plików .

Możesz robić setopt KSH_GLOBi używać wzorców przypominających bash. Lub,

% setopt EXTENDED_GLOB
% obrazów echa / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
% echo images / * ~ * .jpg
images / 004.bmp images / 2252.png

Tak x~ydopasowuje wzorzec x, ale wyklucza wzór y. Ponownie, aby uzyskać szczegółowe informacje, patrz strona podręcznika.


ryby nowe!

Ryba skorupa ma dużo ładniejszą odpowiedź do tego:

🐟 cp (ciąg pasujący -v '* .excluded.names' - srcdir / *) destdir

Dodatkowa wskazówka

Wpisz cp *, naciśnij CtrlX*i zobacz, co się stanie. to nie jest szkodliwe , obiecuję

ulidtko
źródło
@MikhailGolubtsov, być może dlatego, że globowanie nie jest rekurencyjne i działa jeden poziom na raz. Edytowane. PS: choć działa zsh.
ulidtko
3
Niezła propozycja! W ten sposób możesz łatwo usunąć pojedyncze elementy. Wielkie dzięki!
taffit
BTW, aby wyłączyć rozszerzone funkcje dopasowywania wzorców w Bash, uruchom setopt -u extglob.
Rockallite,
49

rsyncPo co korzystać, kiedy możesz:

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

Zakłada się, że struktura katalogu docelowego jest taka sama jak źródła.

Linus Kleen
źródło
8
Myślę, że potrzebujesz -pathargumentu do przetestowania hierarchii ścieżek, a nie -iname
James Murty
3
Na końcu będziesz też potrzebować średnika:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Matthew Wilcoxson
1
Wow, nie pozwoli mi to: „Edycja musi mieć co najmniej 6 znaków”!
Matthew Wilcoxson
1
@MatthewWilcoxson Meh. Ograniczenia te zostaną zniesione, gdy tylko zdobędziesz trochę więcej przedstawicieli. Odpowiednio zredagowałem odpowiedź. Dzięki jeszcze raz!
Linus Kleen
1
@Henning dlaczego nie rsync? Bo może nie być obecny w systemie! natomiast find, cpjest zawsze na swoich miejscach. A może ty od facetów, którzy zainstalowali 2 gigabajty rzeczy, aby robić proste rzeczy?
Reishin,
37
cp -r `ls -A | grep -v "c"` $HOME/
kumar z winogron
źródło
1
Pracował dla mnie w systemie Windows 10 .sh
atwellpub
Utworzono funkcję powłoki, która upraszcza użycie niestandardowej ścieżki źródłowej i wykluczenie tylko jednego pliku lub katalogu: # $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
zawodzi z katalogami ze spacjami
Sérgio
27

Najłatwiejszy sposób, w jaki znalazłem, gdzie można skopiować wszystkie pliki oprócz plików i folderów, po prostu dodając ich nazwy w nawiasach:

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/
Securecurve
źródło
9
Nie działa dla mnie. Dostaję-bash: !: event not found
genorama
8
shopt -s extglob (wykonaj to, aby włączyć! w cp, rm i innych)
imkost
13

Rozszerzając komentarz mvds , to działa dla mnie

cd dotfiles
tar -c --exclude .git --exclude README . | tar -x -C ~/dotfiles2
Steven Penny
źródło
10

Jest względny do katalogu źródłowego.
Spowoduje to wykluczenie source/.gitkopiowania katalogu .

rsync -r --exclude '.git' source target
Niyaz Ahmed Qureshi
źródło
Jaka jest różnica / poprawa w porównaniu do najwyższej odpowiedzi?
ograniczenie aktywności
8

rsync

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

i najpierw spróbuj z opcją -n, aby zobaczyć, co zostanie skopiowane

dzon
źródło
Jaka jest różnica / poprawa w porównaniu do najwyższej odpowiedzi?
ograniczenie aktywności
7

Zakładam, że używasz bash lub dash. Czy to zadziała?

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

Wykonanie polecenia ls z wyłączeniem plików, których nie chcesz, i użycie go jako pierwszego argumentu dla cp

Vanwaril
źródło
9
Możesz pominąć dodatkowe lsi po prostu zrobić cp !(file1|file1) dest.
Shawn Chin
Nie używaj opcji -laR. dodaje ciąg, który koliduje z cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL,
5

Inną prostszą opcją jest instalacja i użycie rsync, który ma opcję --exclude-dir i może być używany zarówno do plików lokalnych, jak i zdalnych.

ehudokai
źródło
4

rsyncjest w rzeczywistości dość trudne. muszę wykonać wiele testów, aby to zadziałało.

Powiedzmy, że chcesz skopiować /var/www/htmldo /var/www/devale muszą wykluczyć /var/www/html/site/video/ katalog może ze względu na swoją wielkość. Poleceniem byłoby:

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

Niektóre zastrzeżenia :

  1. /Potrzebny jest ostatni ukośnik w źródle, w przeciwnym razie skopiuje on również katalog źródłowy, a nie jego zawartość i stanie się /var/www/dev/html/xxxx, co może nie jest tym, czego chcesz.
  2. The --excludeścieżka jest względna do źródła bezpośrednio. Nawet jeśli podasz pełną ścieżkę absolutną, to nie zadziała.

  3. -vjest dla pełnego, -asłuży do trybu archiwizacji, co oznacza, że ​​chcesz rekurencji i chcesz zachować prawie wszystko.

LeOn - Han Li
źródło
proste rozwiązanie, które troszczy się o znaki specjalne i białe znaki
Sérgio
Dziękujemy za wyjaśnienie parametrów, w przeciwieństwie do bieżącej najlepszej odpowiedzi!
ograniczenie aktywności
3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

Edycja: zapomniałem również wykluczyć ścieżkę docelową (w przeciwnym razie rekurencyjnie skopiuje).

praca sudo
źródło
4
uważaj na wpisy katalogu zawierające spacje.
Paulo Scardine
3

To modyfikacja odpowiedzi Linusa Kleena. Jego odpowiedź nie działała dla mnie, ponieważ będzie. dodane przed ścieżką do pliku, której nie lubi cp (ścieżka wyglądałaby jak source / .destination / file).

To polecenie działało dla mnie:

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

polecenie --parents zachowuje strukturę katalogów.

Milan Simek
źródło
2

Po prostu przenieś go tymczasowo do ukrytego katalogu (i zmień jego nazwę później, jeśli chcesz).

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname
lama12345
źródło
1
Może nie całkiem - ale to jedyna znaleziona tutaj opcja, która działa ze cpstandardową powłoką POSIX sh.
tomekwi
1
Ta odpowiedź jest dramatycznie niedoceniana. Jest to najbardziej kompatybilna, najłatwiejsza do odczytania i łatwa do zrozumienia odpowiedź. Brawa, nie wiem, dlaczego o tym nie pomyślałem.
Robert Talada
Dzięki @RobertTalada, jak daleko odejdzie odpowiedź? ️‍🌈
lama12345
1
mv tobecopied/tobeexcluded .
cp -r tobecopied dest/
mv tobeexcluded tobecopied/
John Smith
źródło
0

Używam pętli „do while”, aby odczytać dane wyjściowe polecenia find. W tym przykładzie dopasowuję (zamiast wykluczam) pewne wzorce, ponieważ istnieje bardziej ograniczona liczba dopasowań wzorców, których chcę, niż których nie chcę. Możesz odwrócić logikę z -not przed flagami -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

Korzystam z powyższego, aby skopiować wszystkie pliki typu muzyki, które są nowsze na moim serwerze niż pliki w Western Digital TV Live Hub, które zamontowałem w / media / wd. Używam powyższego, ponieważ mam wiele plików DVD, MPEG, itp., Które chcę wykluczyć ORAZ z jakiegoś powodu rsync wygląda na to, że kopiuje, ale po spojrzeniu na urządzenie wd, pliki nie są tam pomimo braku błędy podczas rsync z tym poleceniem:

    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/
użytkownik3610268
źródło
0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

Pierwsza część to lswszystkie pliki, ale ukryte określone pliki z flagą -I. Wyjście lsjest używane jako standardowe wejście dla drugiej części. xargsbuduj i wykonuj polecenia cp -rf -t destdirze standardowego wejścia. flaga -roznacza kopiowanie katalogów rekurencyjnie, -foznacza kopiowanie plików siłą, które zastąpią pliki w destdir, -tokreśl docelową kopię katalogu do.

LouisXW
źródło
0

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

Shashwot Risal
źródło