Como usar o comando 'cp' para excluir um diretório específico?

411

Quero copiar todos os arquivos em um diretório, exceto alguns arquivos em um subdiretório específico. Notei que o comando 'cp' não tinha uma opção --exclude. Então, como posso conseguir isso?

David Liu
fonte
18
rsync?
precisa saber é
6
tar -c | tar -x?
mvds
1
@mvds, concordo com você, usar tar com '--exclude' é uma boa ideia.
Huang F. Lei

Respostas:

704

O rsync é rápido e fácil:

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

Você pode usar --excludemúltiplos tempos.

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

Observe que a opção dir thefoldertoexcludeafter --excludeé relativa a sourcefolder, ie sourcefolder/thefoldertoexclude,.

Além disso, você pode adicionar -npara execução a seco para ver o que será copiado antes de executar a operação real e, se estiver tudo bem, remova-o -nda linha de comando.

hank
fonte
3
Acordado, você não pode bater a simplicidade e poder de--exclude
Matthew Wilcoxson
31
é o thefoldertoexcludeparente sourcefolderou o diretório de trabalho atual? graças
Beebee
46
É relativo à pasta de origem. Isso excluirá a origem da pasta / .git de ser copiada. rsync -r
exclui o
15
Talvez eu esteja errado, mas acho uma boa prática adicionar "opções" antes de "parâmetros". Além disso, a página de manual dos relatórios rsync --exclude utilizável como com a sintaxe "=" ou sem. Portanto, para padronizar os sistemas operacionais, eu usaria rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder- de qualquer maneira, voto positivo para o rsync, em vez da localização, pois você pode facilmente usar caminhos absolutos para a fonte, enquanto a localização é mais complicada, pois usa {}o dst.
Xavi Montero
1
@mamun É claro exemplo de servidor remoto para máquina local: $ rsync [email protected]:/var/www/mypage /var/www/mylocalpage/ou de local para remoto$ rsync /var/www/mylocalpage/ [email protected]:/var/www/mypage
sobi3ch
84

Bem, se a exclusão de certos padrões de nome de arquivo tivesse que ser executada por todo utilitário de arquivo unix-ish (como cp, mv, rm, tar, rsync, scp, ...), uma imensa duplicação de esforço ocorreria. Em vez disso, essas coisas podem ser feitas como parte do globbing , ou seja, pela sua concha.

bater

man 1 bash, / extglob .

Exemplo:

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

Então você coloca um padrão dentro !(), e isso anula a correspondência. O padrão pode ser arbitrariamente complexo, a partir da enumeração de caminhos individuais (como Vanwaril mostra em outra resposta): !(filename1|path2|etc3)para coisas semelhantes a expressões regulares com estrelas e classes de caracteres. Consulte a página de manual para obter detalhes.

zsh

man 1 zshexpn, / geração de nome de arquivo .

Você pode fazer setopt KSH_GLOBe usar padrões semelhantes ao bash. Ou,

% setopt EXTENDED_GLOB
% de imagens de eco / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
% imagens de eco / * ~ * .jpg
images / 004.bmp images / 2252.png

Então x~ycorresponde ao padrão x, mas exclui o padrão y. Mais uma vez, para obter detalhes completos, consulte a página de manual.


peixe novo!

A casca do peixe tem uma resposta muito mais bonita para isso:

🐟 cp (sequência de caracteres -v '* .excluded.names' - srcdir / *) destdir

Dica profissional de bônus

Digite cp *, clique CtrlX*e veja o que acontece. não é prejudicial eu prometo

ulidtko
fonte
@MikhailGolubtsov talvez seja porque o globbing não seja recursivo e funcione um nível de cada vez. Editado. PS: funciona zshembora.
11135 ulidtko
3
Boa dica profissional! Dessa forma, você pode remover itens individuais facilmente. Muito obrigado!
Taffit
BTW, para desativar os recursos estendidos de correspondência de padrões no Bash, execute setopt -u extglob.
Rockallite
49

Por que usar rsyncquando você pode fazer:

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

Isso pressupõe que a estrutura de diretórios de destino seja igual à da origem.

Linus Kleen
fonte
8
Acho que você precisa o -pathargumento para hierarquias de caminho de teste, não -iname
James Murty
3
E você também precisará de um ponto e vírgula no final:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Matthew Wilcoxson 14/02
1
Uau, isso não me permite: "As edições devem ter pelo menos 6 caracteres"!
Matthew Wilcoxson
1
@MatthewWilcoxson Meh. Essas restrições serão levantadas assim que você ganhar um pouco mais de rep. Eu editei a resposta em conformidade. Obrigado novamente!
Linus Kleen
1
@ Henning, por que não rsync? Porque pode não estar presente no sistema! enquanto find, cpestá sempre em seus lugares. Ou você é do tipo de pessoa que instalou 2 galhos de coisas para fazer coisas simples?
Reishin
37
cp -r `ls -A | grep -v "c"` $HOME/
Vineet Kumar
fonte
1
Trabalhou para mim no Windows 10 .sh
atwellpub
Feito uma função shell que simplifica o uso para caminho de origem personalizado e exclusão de apenas um arquivo ou pasta: # $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
falha com diretórios com espaços
Sérgio
27

A maneira mais fácil que encontrei, onde você pode copiar todos os arquivos, excluindo arquivos e pastas, apenas adicionando seus nomes entre parênteses:

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/
securecurve
fonte
9
Não funciona para mim. Eu recebo-bash: !: event not found
geneorama 04/04
8
shopt -s extglob (executar este para permitir em cp, rm e outros!)
imkost
13

Expandindo o comentário do mvds , isso funciona para mim

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

É relativo ao diretório de origem.
Isso excluirá o diretório source/.gitde ser copiado.

rsync -r --exclude '.git' source target
Niyaz Ahmed Qureshi
fonte
Qual é a diferença / melhoria em comparação com a resposta principal?
reduzindo a atividade
8

rsync

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

e primeiro tente com a opção -n para ver o que será copiado

dzon
fonte
Qual é a diferença / melhoria em comparação com a resposta principal?
reduzindo a atividade
7

Presumo que você esteja usando bash ou dash. Isso funcionaria?

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

Fazendo um ls excluindo os arquivos que você não deseja e usando isso como o primeiro argumento para cp

Vanwaril
fonte
9
Você pode pular o extra lse simplesmente fazer cp !(file1|file1) dest.
Shawn Chin
Não use -laR. ele adiciona uma string que interfere no cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL
5

Outra opção mais simples é instalar e usar o rsync, que possui uma opção --exclude-dir e pode ser usado para arquivos locais e remotos.

ehudokai
fonte
4

rsyncé realmente bastante complicado. precisa fazer vários testes para fazê-lo funcionar.

Vamos dizer que você deseja copiar /var/www/htmlpara /var/www/devmas necessidade de excluir /var/www/html/site/video/ diretório talvez devido ao seu tamanho. O comando seria:

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

Alguma ressalva :

  1. A última barra /na fonte é necessária; caso contrário, ela também copiará o diretório de origem, em vez de seu conteúdo e se tornará /var/www/dev/html/xxxx, o que talvez não seja o que você deseja.
  2. O --excludecaminho é relativo à fonte diretamente. Mesmo se você colocar o caminho absoluto completo, ele não funcionará.

  3. -vé detalhado, -aé para o modo de arquivo, o que significa que você deseja recursão e deseja preservar quase tudo.

LeOn - Han Li
fonte
uma solução simples que tomar cuidados de caracteres especiais e espaços brancos
Sérgio
Obrigado por explicar os parâmetros, diferente da resposta atual atual!
reduzindo a atividade
3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

Editar: esqueceu de excluir também o caminho de destino (caso contrário, ele copiaria recursivamente).

trabalho sudo
fonte
4
atente para as entradas de diretório que contêm espaços.
Paulo Scardine
3

Esta é uma modificação da resposta de Linus Kleen. Sua resposta não funcionou para mim porque haveria um. adicionado na frente do caminho do arquivo que o cp não gosta (o caminho seria semelhante ao código-fonte / .destination / file).

Este comando funcionou para mim:

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

o comando --parents preserva a estrutura de diretórios.

Milan Simek
fonte
2

Apenas mova-o temporariamente para um diretório oculto (e renomeie-o depois, se desejado).

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname
lama12345
fonte
1
Talvez não seja bonito - mas esta é a única opção que encontrei aqui que funciona com cpum shell POSIX padrão sh.
tomekwi
1
Esta resposta é dramaticamente subestimada. Essa é a resposta mais compatível, mais fácil de ler e mais fácil de entender. Parabéns, não sei por que não pensei nisso.
Robert Talada
Obrigado @RobertTalada, até onde vai a resposta agora? ️‍🌈
lama12345
1
mv tobecopied/tobeexcluded .
cp -r tobecopied dest/
mv tobeexcluded tobecopied/
John Smith
fonte
0

Eu uso um loop "do while" para ler a saída do comando find. Neste exemplo, estou correspondendo (em vez de excluir) determinados padrões, pois há um número mais limitado de correspondências de padrão que eu quero do que não quero. Você pode reverter a lógica com um -not na frente dos sinalizadores -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

Utilizo o acima para copiar todos os arquivos de tipo de música que são mais recentes no meu servidor que os arquivos em um Western Digital TV Live Hub que eu montei em / media / wd. Eu uso o acima exposto porque tenho muitos arquivos de DVD, mpegs etc. que desejo excluir E porque, por algum motivo, o rsync parece estar copiando, mas depois de olhar para o dispositivo wd, os arquivos não estão lá, apesar de não haver erros durante o rsync com este comando:

    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/
user3610268
fonte
0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

A primeira parte de lstodos os arquivos, mas oculta arquivos específicos com sinalizador -I. A saída de lsé usada como entrada padrão para a segunda parte. xargsconstruir e executar comando a cp -rf -t destdirpartir da entrada padrão. o sinalizador -rsignifica copiar diretórios recursivamente, -fsignifica copiar arquivos à força que sobrescreverá os arquivos no destdir, -tespecifique o diretório de destino para o qual copiar.

LouisXW
fonte
0

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

Shashwot Risal
fonte