compare 2 diretórios e copie as diferenças em um terceiro diretório

32

Executando o ubuntu 12.04, quero comparar 2 diretórios, digamos folder1 / e folder2 / e copiar todos os arquivos diferentes da pasta3 /. Também existem arquivos aninhados, portanto, os subdiretórios correspondentes também devem ser copiados

Existe um único comando que me ajudaria? Posso obter a lista completa dos arquivos alterados em execução:

rsync -rcnC --out-format="%f" folder1/ folder2/

Mas o rsync parece não ter a capacidade de "exportar" esses arquivos em um diretório de destino diferente. Posso canalizar a lista para cp ou algum outro programa, para que os arquivos sejam copiados, enquanto os diretórios também são criados? Por exemplo, eu tentei

rsync -rcnC --out-format="%f" folder1/ folder2/ | xargs cp -t folder3/

mas isso não preservaria os diretórios também, simplesmente copiaria todos os arquivos dentro da pasta3 /

periklis
fonte
Eu provavelmente usaria uma combinação de diff -qre awkpara construir a lista, então rsync...
ewwhite
como eu usaria o rsync com a lista?
Periklis
Eu executaria um loop for ou usaria a rsync --include-from=FILEopção
precisa saber é o seguinte
(não seja preguiçoso ...) Mas a solução rsync abaixo é elegante.
ewwhite

Respostas:

38

Use --compare-dest.

Na página do manual:

--compare-dest = DIR - Esta opção instrui o rsync a usar o DIR na máquina de destino como uma hierarquia adicional para comparar os arquivos de destino com as transferências (se os arquivos estiverem ausentes no diretório de destino). Se um arquivo for encontrado no DIR idêntico ao arquivo do remetente, o arquivo NÃO será transferido para o diretório de destino. Isso é útil para criar um backup escasso de apenas arquivos que foram alterados em um backup anterior.

primeiro verifique sua sintaxe com --dry-run

rsync -aHxv --progress --dry-run --compare-dest=folder2/ folder1/ folder3/

Então, quando estiver satisfeito com a saída:

rsync -aHxv --progress  --compare-dest=folder2/ folder1/ folder3/

este link tem uma boa explicação do escopo --compare-dest.

ferreiro
fonte
1
Obrigado por isso, eu não tinha entendido a explicação da página de manual deste parâmetro. Para qualquer pessoa interessada, eu fiz isso comrsync -rcC --compare-dest=folder2/ folder1/ folder3/
periklis 17/05
nota rápida para usuários do OsX. Eu tenho rsync version 3.1.1 protocol version 31no meu local e rsync não entende ~/caminhos para --compare-destparam.
Jevgeni Smirnov
4
Para mim, --compare-destexigia um caminho absoluto.
palswim
Não funcionou para mim com as opções do autor ou do OP. Ou seja, ele gera o fonts/Makefile.inarquivo, que é idêntico nos dois folder2e nos folder1diretórios.
Hi-Angel
3

Este pequeno script deve funcionar:

folder1="firsts_folder/"
folder2="second_folder/"
folder3="target_folder"
for x in `rsync -rcnC --out-format="%n"  $folder1 $folder2`
    do
        if [ -d "$folder1/$x" ]; then
            mkdir -p "$folder3/$x"
        else
            cp -frv $folder1/$x $folder3/$x
        fi
done

Mas também acho que analisar a saída do diff -qr seria uma solução melhor, pois fornece o caminho e o nome de cada arquivo de forma consistente.

EDITAR

Este seria um comando, seu comando ligeiramente modificado. Mas isso criará folder1sob o folder3. E ele não funciona com caminhos completos, mas também o script acima não funciona com caminhos completos.

rsync -rcnC --out-format="\"%f\"" folder1/ folder2/ | xargs cp --parents -rfvt folder3/

I utilizado \"em rsyncfazê-lo funcionar com arquivos e diretórios contendo espaços em branco. Testado no Ubuntu 10.04. Espero que ajude.

Laurentiu Roescu
fonte
obrigado por isso, eu esperava que um único comando existiria embora
Periklis
2
rsync -rcnC --out-format="%f" . ../folder2/ |xargs cp --parents -rt ../folder3/

Essa é a forma mais simples que eu poderia criar, se você estiver disposto a descer folder1antes de emitir o comando.

Esta é a opção mais lenta , mas acredito que ela atende aos seus requisitos e pode ser executada usando nomes de diretório não relativos:

rsync -rcnC --out-format="%n" folder1/ folder2/ |grep -vP "/$" |xargs -I{} rsync -R folder1/./{} folder3/

Deixei seu rsynccomando original sozinho, porque você disse que estava fornecendo a lista de arquivos correta (e meus arquivos de teste são obviamente diferentes dos seus, portanto, não podia ter certeza de que estaria obtendo a lista de arquivos correta se eu estragasse com isso).

O grepque há para remover nomes de diretório a partir da saída rsync.

A saída de grepé então canalizada para outra rsyncutilização xargs. No parâmetro, folder1/./{}o extra ./é usado para dizer ao rsync para criar os diretórios relativos começando por ./{}ignorar folder1/. Em outras palavras, evita a criação folder3/folder1/.

Eu só pude testar isso no CentOS 6.4, mas o AFAIK deve funcionar da mesma maneira no Ubuntu 12.04.

EDIT: Devo observar que a resposta do smithian é sem dúvida melhor, mas eu queria tentar fazê-lo com o seu rsynccomando original no tato, pois estava fornecendo a saída desejada.

s.co.tt
fonte