Eu tenho duas unidades com os mesmos arquivos, mas a estrutura de diretórios é totalmente diferente.
Existe alguma maneira de 'mover' todos os arquivos no lado de destino para que eles correspondam à estrutura do lado de origem? Com um roteiro, talvez?
Por exemplo, a unidade A possui:
/foo/bar/123.txt
/foo/bar/234.txt
/foo/bar/dir/567.txt
Enquanto a unidade B possui:
/some/other/path/123.txt
/bar/doo2/wow/234.txt
/bar/doo/567.txt
Os arquivos em questão são enormes (800 GB), então não quero copiá-los novamente; Eu só quero sincronizar a estrutura criando os diretórios necessários e movendo os arquivos.
Eu estava pensando em um script recursivo que encontrasse cada arquivo de origem no destino e depois o movesse para um diretório correspondente, criando-o, se necessário. Mas - isso está além das minhas habilidades!
Outra solução elegante foi fornecida aqui: /superuser/237387/any-way-to-sync-directory-structure-when-the-files-are-already-on-both-sides/238086
Respostas:
Vou com Gilles e aponto para Unison, como sugerido por hasen j . O Unison foi o DropBox 20 anos antes do DropBox. Código sólido que muitas pessoas (inclusive eu) usam todos os dias - vale a pena aprender. Ainda assim,
join
precisa de toda a publicidade que puder obter :)Esta é apenas meia resposta, mas tenho que voltar ao trabalho :)
Basicamente, eu queria demonstrar o
join
utilitário pouco conhecido que faz exatamente isso: junta duas tabelas em um determinado campo.Primeiro, configure um caso de teste incluindo nomes de arquivos com espaços:
(edite alguns nomes de diretório e / ou arquivo
new
).Agora, queremos criar um mapa: hash -> nome do arquivo para cada diretório e, em seguida, usar
join
para combinar arquivos com o mesmo hash. Para gerar o mapa, coloque o seguinte emmakemap.sh
:makemap.sh
cospe um arquivo com as linhas do formulário, 'hash "filename"', então juntamos a primeira coluna:Isso gera o
moves.txt
seguinte:O próximo passo seria realmente fazer as jogadas, mas minhas tentativas ficaram presas na citação ...
mv -i
emkdir -p
devem ser úteis.fonte
join
é realmente interessante. Obrigado por chamar minha atenção.join
entrada?Há um utilitário chamado uníssono:
http://www.cis.upenn.edu/~bcpierce/unison/
Descrição do site:
Observe que o Unison detecta apenas arquivos movidos na primeira execução se pelo menos uma das raízes for remota; portanto, mesmo que você esteja sincronizando arquivos locais, use-as
ssh://localhost/path/to/dir
como uma das raízes.fonte
Use Unison, como sugerido por hasen j . Deixo esta resposta como um exemplo de script potencialmente útil ou para uso em um servidor com apenas utilitários básicos instalados.
Suponho que os nomes dos arquivos sejam únicos em toda a hierarquia. Também assumirei que nenhum nome de arquivo contém uma nova linha e que as árvores de diretório contêm apenas diretórios e arquivos regulares.
Primeiro colete os nomes dos arquivos no lado da fonte.
Em seguida, mova os arquivos no lugar no lado do destino. Primeiro, crie uma árvore de arquivos achatada no lado do destino. Use em
ln
vez demv
se você deseja manter os links físicos na hierarquia antiga.Se alguns arquivos estiverem ausentes no destino, crie um nivelamento similar
/A.staging
e use o rsync para copiar os dados da origem para o destino.Agora renomeie os arquivos no lugar.
Equivalentemente:
Por fim, se você se importa com os metadados dos diretórios, chame rsync com os arquivos já existentes.
Observe que não testei os trechos desta postagem. Use por sua conta e risco. Por favor, reporte qualquer erro em um comentário.
fonte
Particularmente, se a sincronização contínua for útil, você pode tentar descobrir o git-anexo .
É relativamente novo; Eu não tentei usá-lo sozinho.
Eu posso sugerir isso porque evita manter uma segunda cópia dos arquivos ... isso significa que ele precisa marcar os arquivos como somente leitura ("bloqueados"), como certos sistemas de controle de versão que não são do Git.
Os arquivos são identificados pela extensão sha256sum + (por padrão). Portanto, ele deve ser capaz de sincronizar dois repositórios com conteúdo de arquivo idêntico, mas com nomes de arquivos diferentes, sem precisar executar gravações (e em uma rede de baixa largura de banda, se desejado). Obviamente, terá que ler todos os arquivos para soma de verificação.
fonte
Que tal algo como isso:
Isso pressupõe que os nomes dos arquivos que você deseja sincronizar sejam únicos em toda a unidade: caso contrário, não há como ele ser totalmente automatizado (no entanto, você pode fornecer um prompt para o usuário escolher qual arquivo escolher, se houver mais).
O script acima funcionará em casos simples, mas poderá falhar se
name
contiver símbolos que tenham um significado especial para regexps. Agrep
lista de arquivos também pode levar muito tempo se houver muitos arquivos. Você pode traduzir esse código para usar hashtable, que mapeará nomes de arquivos para caminhos, por exemplo, em Ruby.fonte
grep
linha faz? Apenas encontra o caminho completo do arquivo correspondentedstlist
?ln
dele cria links simbólicos. Você pode empregarmv
para mover os arquivos, mas cuidado com a substituição dos arquivos existentes. Além disso, convém limpar os diretórios vazios, se houver, depois de mover os arquivos. Sim, essegrep
comando procura uma linha que termine no nome do arquivo, revelando assim o caminho completo para ele na unidade de destino.Supondo que os nomes de arquivos base sejam únicos nas árvores, é bastante simples:
Se você deseja limpar os diretórios vazios antigos, use:
fonte
Eu também enfrentei esse problema. A solução baseada em md5sum não funcionou para mim, porque sincronizo meus arquivos para uma
webdav
montagem. A computação de somas md5sum nowebdav
destino também significaria operações de arquivos grandes.Eu criei um pequeno script
reorg_Remote_Dir_detect_moves.sh
(no github) que está tentando detectar os arquivos mais movidos e, em seguida, cria um novo shell-script temporário com vários comandos para ajustar o diretório remoto. Como só cuido dos nomes dos arquivos, o script não é uma solução perfeita.Por segurança, vários arquivos serão ignorados: A) Arquivos com os mesmos nomes (do mesmo começo) em todos os lados e B) Arquivos que estão apenas no lado remoto. Eles serão ignorados e ignorados.
Os arquivos ignorados serão tratados pela sua ferramenta de sincronização preferida (por exemplo
rsync, unison
, ...), que você deverá usar após executar o shell-script temporário.Talvez meu script seja útil para alguém? Nesse caso (para tornar mais claro), existem três etapas:
reorg_Remote_Dir_detect_moves.sh
(no github)/dev/shm/REORGRemoteMoveScript.sh
=> execute isso para executar as movimentações (será rápido na montagemwebdav
)rsync, unison
, ...)fonte
Aqui está minha tentativa de resposta. Como aviso prévio, toda a minha experiência com scripts vem do bash; portanto, se você estiver usando um shell diferente, os nomes ou a sintaxe dos comandos poderão ser diferentes.
Esta solução requer a criação de dois scripts separados.
Esse primeiro script é responsável por mover os arquivos na unidade de destino.
O segundo script cria o arquivo de mapa md5 usado pelo primeiro script e chama o primeiro script em todos os arquivos na unidade de destino.
Basicamente, o que está acontecendo é que os dois scripts simulam uma matriz associativa
$md5_map_file
. Primeiro, todos os MD5s para os arquivos na unidade de origem são calculados e armazenados. Associados aos md5s estão os caminhos relativos da raiz da unidade. Em seguida, para cada arquivo na unidade de destino, o md5 é calculado. Usando esse md5, o caminho desse arquivo na unidade de origem é pesquisado. O arquivo na unidade de destino é então movido para corresponder ao caminho do arquivo na unidade de origem.Existem algumas ressalvas neste script:
fonte
md5sum
parece não ser o item a ser usado aqui. (BTW,rsync
tem um modo no qual não calcula somas de verificação).