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ąć?



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.


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 user@example.com:/var/www/mypage /var/www/mylocalpage/lub z lokalnego na zdalny$ rsync /var/www/mylocalpage/ user@example.com:/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ę


@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.


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/

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/

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



8

rsync

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

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


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


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.


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.


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).


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.


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

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/

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/

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.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.