CLI AI

Copiar arquivos por padrão, mantendo a estrutura de pastas

2026-07-06

Resposta curta: cp --parents e rsync copiam os mesmos arquivos, mas constroem árvores de destino diferentes. find src -name '*.txt' -exec cp --parents {} dst/ \; os coloca em dst/src/a/b/file; a versão com rsync e include/exclude coloca os mesmos arquivos em dst/a/b/file — sem o segmento src. Escolha o método errado e você ganha um nível extra de aninhamento que ninguém avisou.

1. Como copio arquivos que correspondem a um padrão mantendo a estrutura de pastas?

clai
$ clai copia todos os arquivos txt de src para dst, mantendo a estrutura de pastas→ find src -name '*.txt' -exec cp --parents {} dst/ \;

--parents reconstrói o caminho completo até o arquivo dentro do destino. O resultado é dst/src/a/b/file: o próprio src acaba dentro do destino, porque faz parte do caminho que você passou ao find. É essa a surpresa de que trata este artigo.

2. Por que o rsync monta uma árvore de destino diferente para a mesma tarefa?

clai
$ clai copia só os arquivos txt de src para dst2, mantendo o aninhamento→ rsync -a --include='*/' --include='*.txt' --exclude='*' src/ dst2/

Mesmos arquivos, resultado diferente: dst2/a/b/file, sem o nível src. A barra no final de src/ significa "o conteúdo do diretório", não o diretório em si. A ordem das regras também importa: primeiro libere a travessia de todos os diretórios com --include='*/', depois os arquivos que você quer, e só então exclua o resto. Mova --exclude='*' para o início e nada é copiado.

3. Como verifico o que o rsync vai copiar antes de rodar?

clai
$ clai mostra o que seria copiado, mas não copie nada→ rsync -avn --include='*/' --include='*.txt' --exclude='*' src/ dst2/

-n é um ensaio a seco. Com regras de include e exclude que não são triviais, pular o -n significa descobrir o resultado depois do fato, não antes. Rode -n primeiro, sempre.

4. Como copio arquivos para um servidor remoto com a mesma estrutura?

clai
$ clai leva todos os arquivos txt com a estrutura preservada para um servidor remoto→ find src -name '*.txt' -print0 | tar --null -cf - -T - | ssh user@host 'tar -xf - -C /dest'

tar empacota os arquivos num fluxo e os desempacota do outro lado, com a estrutura intacta como está. -print0 e --null protegem contra espaços nos nomes. Uma passagem pela rede vale mais que mil cópias individuais.

5. Como copio sem sobrescrever arquivos mais novos no destino?

clai
$ clai copia os arquivos mas não mexa nos que estão mais novos no destino→ rsync -au src/ dst/

-u pula qualquer arquivo cuja cópia no destino tenha uma data de modificação mais recente. Necessário quando a sincronização roda nas duas direções, ou quando o destino já tem edições que você não quer perder.

6. Como recrio só a árvore de diretórios, sem os arquivos?

clai
$ clai cria em dst a mesma árvore de pastas que existe em src, sem os arquivos→ rsync -a --include='*/' --exclude='*' src/ dst/

Mesmas regras, menos a linha que deixa passar os arquivos. Útil para preparar uma árvore que vai receber uma saída — antes de uma conversão de imagens em lote, por exemplo.

Pegadinhas

  • A barra no final da origem muda tudo no rsync. src/ copia o conteúdo; src copia o próprio diretório para dentro do destino. Um dos erros mais comuns, e é silencioso.
  • A ordem de include e exclude é a ordem das regras. O rsync aplica a primeira que combinar. --exclude='*' sempre vai por último, senão engole tudo antes de os includes terem chance.
  • cp --parents só existe no GNU. Não existe no macOS — use ali a versão com rsync ou tar.

Perguntas relacionadas

Como copio várias extensões de uma vez? Repita --include: --include='*.jpg' --include='*.png' antes de --exclude='*'.

Por que o rsync não copiou nada? Quase sempre falta --include='*/': sem ele, o rsync nunca entra nos subdiretórios, então nunca chega aos arquivos.

cp ou rsync? rsync quando as regras passam de uma extensão, quando você quer um ensaio a seco, ou quando a cópia pode ser interrompida. cp para um trabalho rápido, simples e pontual.

Veja também

Descreva a cópia, leia o comando que o CliAI escreve, depois rode. Instale em uma linha.