Como copiar e mesclar dois diretórios?

112

Eu tenho dois diretórios images e images2 com essa estrutura no Linux:

/images/ad  
/images/fe  
/images/foo  

... e outras 4000 pastas

e o outro é como:

/images2/ad  
/images2/fe  
/images2/foo

... e outras 4000 pastas

Cada uma dessas pastas contém imagens e os nomes dos diretórios em imagens e imagens2 são exatamente os mesmos, porém seu conteúdo é diferente. Quero saber como posso mesclar as imagens de / images2 / ad em images / ad, as imagens de / images2 / foo em images / foo e assim por diante com todas as 4000 pastas.

ssierral
fonte
1
os arquivos finais têm o mesmo nome nos dois diretórios?
Simply_Me 12/08
Não ... por exemplo, em imagens / anúncio são 1.jpg, 2.jpg e 3.jpg. Mas, em images2 / ad são 4.jpg e 5.jpg
ssierral
4
@AmirAliAkbari, não acho que seja uma duplicata - a outra pergunta é basicamente 'mv faz mesclagem?' (resposta: não). Esta pergunta é sobre como mesclar 2 hierarquias de diretório.
7606 maxschlepzig

Respostas:

173

Este é um trabalho para o rsync . Não há nenhum benefício em fazer isso manualmente com um loop de shell, a menos que você queira mover o arquivo em vez de copiá-lo.

rsync -a /path/to/source/ /path/to/destination

No seu caso:

rsync -a /images2/ /images/

(Observe a barra à direita images2; caso contrário, ela copiaria para /images/images2.)

Se as imagens com o mesmo nome existir em ambos os diretórios, o comando acima irá substituir /images/SOMEPATH/SOMEFILEcom /images2/SOMEPATH/SOMEFILE. Se você deseja substituir arquivos somente mais velhos, adicione a opção -u. Se você quiser manter sempre a versão em /images, adicione a opção --ignore-existing.

Se você deseja mover os arquivos /images2, com rsync, você pode passar a opção --remove-source-files. Em seguida, o rsync copia todos os arquivos e remove cada arquivo quando terminar. Isso é muito mais lento do que se mover se os diretórios de origem e destino estiverem no mesmo sistema de arquivos.

Gilles
fonte
14
..add -P se você gostaria de ver progresso ..
Meetai.com
1
Gostaria de acrescentar que não há nenhum benefício para usando um loop shell complicado aqui, mesmo se você não quer movê-los em vez de copiá-los-nesse caso é só usar rsync, então rm -r /images.
Curinga
1
Gostaria também de salientar que é importante incluir as barras finais de cada diretório . Por exemplo, se você simplesmente executou rsync -a images images2, ele copiará images2 em imagens em vez de mesclá-las.
Kyle Challis #
1
@ s3cur3 Oh. De 2 a (implícito) 1. Isso não é intuitivo. Obrigado, eu corrigi minha resposta.
Gilles
1
@MaxCoplan Não. O Rsync não é uma ferramenta interativa.
Gilles
43

A melhor opção, como já postada, é, obviamente, o rsync. No entanto, também o uníssono seria um ótimo software para fazer esse trabalho. Ambos podem ser usados ​​em vários sistemas operacionais.

Rsync

O rsync sincroniza em uma direção da origem ao destino. Portanto, a seguinte declaração

rsync -avh --progress Source Destination

sincroniza tudo, desde a origem até o destino . A pasta mesclada reside em Destino .

-a significa "arquivar" e copia tudo recursivamente da origem ao destino, preservando quase tudo.

-v fornece mais saída ("detalhado").

-h para legível por humanos.

- progrida para mostrar quanto trabalho é feito.

Se você deseja atualizar apenas a pasta de destino com arquivos mais recentes da pasta de origem:

rsync -avhu --progress source destination

Uníssono

uníssono sincroniza em ambas as direções. Portanto, a seguinte declaração

unison Source Destination

sincroniza os dois diretórios nas duas direções e, finalmente, a origem é igual ao destino. É como fazer o rsync duas vezes da fonte ao dest e vice-versa.

Para usos mais avançados, consulte as páginas de manual ou os seguintes sites:

  1. https://www.cis.upenn.edu/~bcpierce/unison/
  2. https://rsync.samba.org/
debiarca
fonte
2
Quero mencionar que o caminho correto para a pasta deve estar com a barra no final rsync -avh --progress source/ destination/, caso contrário, a pasta de origem será criada na pasta de destino, pelo menos no meu caso, dessa forma.
electroid
Isso funciona muito bem para mim (com a barra à direita em pastas). Obrigado!
Leopoldo Sanczyk
5
for dir in images2/*; do mv "$dir"/* "images/$(basename "$dir")"; done

Faça um loop sobre todo o conteúdo do images2uso de uma glob expandida (para evitar problemas de análise ls) e, em seguida, mvo conteúdo desses itens na entrada correspondente images. Usa basenamepara remover a liderança images2do caminho globbed.

Etan Reisner
fonte
por favor, adicionar mais detalhes sobre o seu comando faz isso que é útil para futuros leitores também :)
Ramesh
1

@ inulinux12, você pode usar o seguinte forloop de uma linha da linha de comando:

$ for dir in images2/*; do mv "$dir"/* "${dir/2/}"; done

Isso moverá todos os arquivos de images2para imagesem seus respectivos diretórios. Nota: isso pressupõe que nenhum arquivo tenha o mesmo nome.

Por exemplo:

Antes da execução:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2
images/adfoo:
jpg.7
images/fe:
jpg.5
images2:
ad  adfoo  fe
images2/ad:
jpg.3
images2/adfoo:
jpg.6
images2/fe:
jpg.4

Após a execução:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2  jpg.3
images/adfoo:
jpg.6  jpg.7
images/fe:
jpg.4  jpg.5
Simplesmente eu
fonte
3
Não analise a saída de ls. mywiki.wooledge.org/ParsingLs
Etan Reisner
@EtanReisner Obrigado pela sugestão; parece cenários bastante estreitos, apesar das informações fornecidas na pergunta.
Simply_Me
2
@Simply_Me Embora seja verdade que geralmente tudo vai dar certo, você realmente não quer que isso exploda quando você bate em um caso em que não estava contando. Isso pode causar problemas muito ruins. Sem mencionar que é quase sempre (como neste caso) quase trivialmente substituível por uma simples glob. Veja minha resposta como um exemplo disso.
Etan Reisner
@Simply_Me Os cenários incluem nomes de arquivos com espaços, o que é bastante comum para imagens.
Gilles
@Gilles e @Etan Reisner, obrigado pela contribuição, agradeço! Atualizei e testei minha resposta para usar a substituição de cadeias, e chegou a ser mais rápido do que usar basenamenessa situação específica (não é necessário pedir basenameisso). Obrigado novamente por comentários construtivos.
Simply_Me 13/08/14