mv com funcionalidade rsync

5

Estou tentando mesclar duas árvores de diretórios que possuem muitos elementos comuns, mas também cada um deles possui elementos que estão presentes apenas em uma das duas árvores. O principal problema que estou tendo é que quando mv encontra dois subdiretórios com os mesmos caminhos relativos, ele mantém a origem (com -f ) ou o destino (com -n ), mas não consigo fazer isso a união de ambos os subdiretórios. Eu poderia, claro, usar rsync com --remove-source-files , mas isso irá realmente copiar os dados e, em seguida, excluir os arquivos antigos, em vez de um movimento verdadeiro. As duas árvores de diretórios contêm várias centenas de GB de dados e estão na mesma partição, então eu adoraria fazer um movimento verdadeiro, se possível, por causa do tempo.

Agora, tenho find * -type file -exec mv -n {} /destination/{} , mas isso só move os arquivos da origem para o destino quando o diretório de destino já existe. Eu posso começar este comando com algo como mv -n * /destination/ , mas isso só traz os diretórios de nível superior. Existe alguma maneira de fazer isso em uma única linha? Eu sempre poderia escrever um script para verificar se o diretório existe antes de copiar o arquivo, mas isso parece uma tarefa tão básica, parece que deve haver uma maneira mais fácil.

    
por Reed Espinosa 28.08.2014 / 19:51

2 respostas

2

Aviso: essa resposta não funcionará em sistemas de arquivos que não oferecem suporte a links físicos (por exemplo, FAT).

Outra opção (que pode ser mais portável) é

cd source_directory
find . -type f -print0 | cpio --pass-through --null --link --make-directories dest_dir

cpio (copiar em & fora) é um dinossauro anterior a tar . Como tar , ele pode criar ou extrair arquivos. Ao contrário de tar (corrija-me se estiver errado) ele pode copiar árvores de diretórios com um único comando. (Eu acho que você poderia fazer isso com tar -cf - source option(s) and arguments(s) | tar -xf - destination option(s) and arguments(s) .) Isso é o que --pass-through significa. --null significa “esperar que nomes de arquivos sejam delimitados por nulos”; isto é, leia a saída de find … -print0 . --link significa "vincular arquivos do diretório de origem ao diretório de destino, se possível". --make-directories não precisa de explicação.

Isso pode ser abreviado como cpio –p0ld dest_dir . Adicione --verbose ou -v , se desejar.

Então, depois disso,

  • Verifique as colisões e manuseie adequadamente.
  • Verifique se o seu diretório de destino está preenchido com links físicos.
  • Remova o diretório de origem.
por 28.08.2014 / 20:51
3

Você pode usar prename para conseguir o que deseja. Em algumas distribuições (por exemplo, Debian / Ubuntu), isso deve ser instalado como padrão e com alias para rename . Outras distros podem usar diferentes rename . Você pode mudar para o diretório acima do diretório de origem e fazer:

find source -exec prename 's:^source:/path/to/dest:' {} +

Isso irá se recusar a mover os arquivos que já existem na árvore de destino e deixar diretórios vazios no caso onde os nomes dos diretórios se sobrepõem, então você terá que removê-los depois. Você pode adicionar a opção -f a prename para sobrescrever arquivos existentes.

Exemplo:

$ mkdir -p dir1/{common,sub1} dir2/{common,sub2}

$ touch dir1/sub1/file dir2/sub2/file dir1/common/common dir2/common/common dir1/common/diff1 dir2/common/diff2

$ tree dir*
dir1
├── common
│   ├── common
│   └── diff1
└── sub1
    └── file
dir2
├── common
│   ├── common
│   └── diff2
└── sub2
    └── file

4 directories, 6 files

$ find dir2 -depth -exec rename 's/^dir2/dir1/' {} +
Can't rename dir2/sub2/file dir1/sub2/file: No such file or directory
dir2/common/common not renamed: dir1/common/common already exists
dir2/common not renamed: dir1/common already exists
dir2 not renamed: dir1 already exists

$ tree dir*
dir1
├── common
│   ├── common
│   ├── diff1
│   └── diff2
├── sub1
│   └── file
└── sub2
    └── file
dir2
└── common
    └── common

4 directories, 6 files

Atualização:

Para fornecer uma fonte para prename , geralmente vem empacotado com perl (daí o 'p'). No Debian / Ubuntu faz parte do pacote perl . Se você deseja obtê-lo separadamente, um dos respondentes dessa pergunta - Obter o utilitário de renomeação de Perl em vez da renomeação integrada criou um repositório separado para ele - link

    
por 28.08.2014 / 20:43

Tags