Copie a pasta recursivamente, excluindo algumas pastas
197
Estou tentando escrever um script simples do bash que copie todo o conteúdo de uma pasta, incluindo arquivos e pastas ocultos em outra pasta, mas quero excluir determinadas pastas específicas. Como eu consegui isso?
Eu imagino algo como encontrar. -name * canalizado para grep / v "padrão de exclusão" para filtrar os que você não deseja e, em seguida, canalizado para o cp para fazer a cópia.
i_am_jorf
1
Eu estava tentando fazer algo assim, mas a figura não poderia descobrir como usar cp com um tubo
trobrock
1
Provavelmente isso deve ir para o superusuário. O comando que você está procurando é xargs. Você também pode fazer algo como dois alcatrões conectados por um cano.
Kyle Butt
1
Talvez seja tarde e ele não responder à pergunta com precisão, mas aqui vai uma dica: Se você quiser excluir as crianças só imediatos do diretório que você poderia tirar proveito do bash padrão de correspondência, por exemplocp -R !(dir1|dir2) path/to/destination
Boris D. Teoharov
1
Observe que o !(dir1|dir2)padrão precisa extglobestar ativado ( shopt -s extglobpara ativá-lo).
Observe que usar sourcee source/é diferente. Uma barra à direita significa copiar o conteúdo da pasta sourcepara destination. Sem a barra final, significa copiar a pasta sourcepara destination.
Como alternativa, se você tiver muitos diretórios (ou arquivos) a serem excluídos, poderá usar --exclude-from=FILE, onde FILEé o nome de um arquivo que contém arquivos ou diretórios a serem excluídos.
--exclude também pode conter curingas, como --exclude=*/.svn*
Sugiro adicionar o --dry-run para verificar quais arquivos serão copiados.
Loretoparisi
1
@AmokHuginnsson - Quais sistemas você está usando? O Rsync está incluído por padrão em todas as distros principais do Linux que eu conheço, incluindo RHEL, CentOS, Debian e Ubuntu, e acredito que também esteja no FreeBSD.
siliconrockstar
1
Para distribuições derivadas do RHEL: yum install rsync ou em versões baseadas no Debian: apt-get install rsync. A menos que você esteja construindo seu servidor com base absoluta em seu próprio hardware, isso não é problema. O rsync também é instalado por padrão nas minhas caixas do Amazon EC2 e nas caixas do ZeroLag e RackSpace.
Siliconrockstar 02/02
2
rsync parece ser extremamente lento em comparação com cp? Pelo menos essa foi a minha experiência.
Kojo
2
Por exemplo, para ignorar o dir git:rsync -av --exclude='.git/' ../old-repo/ .
nycynik 05/04
40
Use alcatrão junto com um cano.
cd /source_directory
tar cf ---exclude=dir_to_exclude .|(cd /destination && tar xvf -)
Essa abordagem desnecessariamente primeiro tarra a fonte de destino (e exclui diretórios específicos no arquivo morto) e depois a tarta no destino. Não recomendado!
Wouter Donders
4
@Waldheri você está errado. essa é a melhor solução. Ele faz exatamente o que o OP solicitou e funciona na instalação padrão da maioria dos sistemas operacionais * nix. Tarar e desarmar é feito em tempo real sem artefato do sistema de arquivos (na memória), o custo desse tar + desarmar é insignificante.
AmokHuginnsson
@WouterDonders O alcatrão é uma sobrecarga mínima. Não aplica compactação.
Kyle Butt
9
Você pode usar findcom a -pruneopção
Um exemplo de man find:
cd / fonte-dir
encontrar . -name .snapshot -une -o \ (\! -name * ~ -print0 \) |
cpio -pmd0 / dest-dir
Este comando copia o conteúdo de / source-dir para / dest-dir, mas omite
arquivos e diretórios denominados .snapshot (e qualquer coisa neles). Isso também
omite arquivos ou diretórios cujo nome termina em ~, mas não seus
tendas. A construção -prune -o \ (... -print0 \) é bastante comum. o
A idéia aqui é que a expressão before -une corresponda a coisas que são
ser podado. No entanto, a própria ação -prune retorna true, portanto, o
-o garante que o lado direito seja avaliado apenas para
os diretórios que não foram removidos (o conteúdo do podado
os diretórios nem são visitados, portanto, seu conteúdo é irrelevante).
A expressão no lado direito do -o está entre parênteses
para maior clareza. Ele enfatiza que a ação -print0 ocorre apenas
por coisas que não tinham - aplicado a eles. Porque o
condição padrão `e 'entre testes se liga mais firmemente que -o, isso
é o padrão de qualquer maneira, mas os parênteses ajudam a mostrar o que está acontecendo
em.
Desculpe, mas eu realmente não entendo por que 5 pessoas votaram nisto quando foi admitidamente não testado e não parecem funcionar em um teste simples: tentei isso em um subdiretório /usr/share/iconse cheguei imediatamente find: paths must precede expression: 22x22onde o último é um dos subdiretores. . Meu comando foi find . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/(na verdade, eu estou no MSYS2, então realmente /mingw64/share/icons/Adwaita, mas eu não posso ver como isso é culpa de MSYS2)
underscore_d
0
EXCLUDE="foo bar blah jah"
DEST=$1
for i in*dofor x in $EXCLUDE
doif[ $x != $i ];then
cp -a $i $DEST
fidonedone
Isto está incorreto. Alguns problemas: Conforme escrito, ele copiará um arquivo que não deve ser excluído várias vezes (o número de itens a serem excluídos, que neste caso é 4). Mesmo se você tentar copiar 'foo', o primeiro item da lista de exclusões, ele ainda será copiado quando você chegar a x = bar e eu ainda estiver foo. Se você insistir em fazer isso sem ferramentas pré-existentes (por exemplo, rsync), mova a cópia para uma instrução if fora do loop 'for x in ...' e faça com que o loop 'for x ...' altere a instrução lógica em o arquivo de cópia if (true). Isso impedirá que você copie várias vezes.
Eric Bringley
0
Inspirado na resposta de SteveLazaridis, que falharia, aqui está uma função shell POSIX - basta copiar e colar em um arquivo nomeado cpxem você $PATHe torná-lo executável ( chmod a+x cpr). [A fonte agora é mantida no meu GitLab .
#!/bin/sh# usage: cpx [-n|--dry-run] "from_path" "to_path" "newline_separated_exclude_list"# limitations: only excludes from "from_path", not it's subdirectories
cpx(){# run in subshell to avoid collisions(_CopyWithExclude"$@")}_CopyWithExclude(){case"$1"in-n|--dry-run){DryRun='echo'; shift;};;esac
from="$1"
to="$2"
exclude="$3"
$DryRun mkdir -p "$to"if[-z "$exclude"];then
cp "$from""$to"returnfi
ls -A1 "$from" \
|while IFS= read -r f;do
unset excluded
if[-n "$exclude"];thenfor x in $(printf "$exclude");doif["$f"="$x"];then
excluded=1breakfidonefi
f="${f#$from/}"if[-z "$excluded"];then
$DryRun cp -R "$f""$to"else[-n "$DryRun"]&& echo "skip '$f'"fidone}# Do not execute if being sourced["${0#*cpx}"!="$0"]&& cpx "$@"
Parece inútil dizer resposta que alguém "seria um fracasso" sem explicar o que está errado com ele e como você corrigir isso ...
underscore_d
@underscore_d: true, em retrospectiva, especialmente porque agora não consigo me lembrar do que falhou :-(
go2null
Múltiplas coisas: (1) copia os arquivos várias vezes e (2) a lógica ainda copia os arquivos a serem excluídos. Execute os loops usando i = foo: ele será copiado 3 vezes em vez de 4 para qualquer outro arquivo, por exemplo, i = test.txt.
Eric Bringley
1
obrigado @EricBringley por esclarecer as deficiências da resposta de Steve. (Ele disse que era testado embora.)
cp -R !(dir1|dir2) path/to/destination
!(dir1|dir2)
padrão precisaextglob
estar ativado (shopt -s extglob
para ativá-lo).Respostas:
Use rsync:
Observe que usar
source
esource/
é diferente. Uma barra à direita significa copiar o conteúdo da pastasource
paradestination
. Sem a barra final, significa copiar a pastasource
paradestination
.Como alternativa, se você tiver muitos diretórios (ou arquivos) a serem excluídos, poderá usar
--exclude-from=FILE
, ondeFILE
é o nome de um arquivo que contém arquivos ou diretórios a serem excluídos.--exclude
também pode conter curingas, como--exclude=*/.svn*
fonte
rsync -av --exclude='.git/' ../old-repo/ .
Use alcatrão junto com um cano.
Você pode até usar essa técnica no ssh.
fonte
Você pode usar
find
com a-prune
opçãoUm exemplo de
man find
:fonte
cpio
ainda não foi empacotado para o MSYS2.você pode usar o tar, com a opção --exclude, e depois descompactá-lo no destino. por exemplo
veja a página de manual do tar para mais informações
fonte
Semelhante à ideia de Jeff (não testada):
fonte
/usr/share/icons
e cheguei imediatamentefind: paths must precede expression: 22x22
onde o último é um dos subdiretores. . Meu comando foifind . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/
(na verdade, eu estou no MSYS2, então realmente/mingw64/share/icons/Adwaita
, mas eu não posso ver como isso é culpa de MSYS2)Não testado...
fonte
Inspirado na resposta de SteveLazaridis, que falharia, aqui está uma função shell POSIX - basta copiar e colar em um arquivo nomeado
cpx
em você$PATH
e torná-lo executável (chmod a+x cpr
). [A fonte agora é mantida no meu GitLab .Exemplo de uso
fonte