
Eu tenho dois diretórios que precisam ser mesclados. Os arquivos nesses dois diretórios são todos arquivos grandes (>= 500 MB).
O que eu quero arquivar: Para arquivos no diretório de origem: se não existir no diretório de destino, mv
vá para o diretório de destino (o que é rápido, pois basicamente estamos criando um novo link físico e desvinculando o arquivo de origem); se existir no diretório de destino, copie o arquivo de origem e remova o arquivo de origem.
A maneira mais comum de mesclar diretórios no sistema Linux é usar a opção rsync
with --remove-source-files
. Mas isso é lento porque fará a operação de cópia mesmo que o arquivo de destino não exista.
Alguma ideia melhor? Obrigado.
Responder1
Basicamente, o que você descreveu é mover arquivos para um destino de substituição, se existir. Então basta movê-los.
Responder2
Há um caso em que mv
falha. Aqui estão alguns dados de exemplo:
mkdir -p src/d dest/d
touch src/d/f1 dest/d/f2
Veja como mv
falha:
$ mv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -f src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi src/* dest/
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi -t dest/ src/*
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty
Então crie um arquivo de script:
vim supermove
Este exemplo não verifica erros (AVISO LEGAL: funciona para mim, mas teste se funciona para você... talvez com echo
before mv
) e substituirá os arquivos com o mesmo caminho. E usa find com \;
o qual é terrivelmente ineficiente, mas +
não funciona bem com "$dest"
prefixo. Versões mais antigas criarão alguns diretórios sem o caminho anexado, e versões mais recentes de find dirão:
find: In '-exec ... {} +' the '{}' must appear by itself, but you specified 'dest/{}'
Você provavelmente poderia encontrar uma maneira de consertar isso com xargs. (Demorou alguns minutos nos arquivos de 64k de 8 TB que eu estava movendo). Adicione este conteúdo:
#!/bin/bash
src=$1
dest=$2
src=$(readlink -f "$src")
dest=$(readlink -f "$dest")
cd "$src"
# also copy hidden files
shopt -s dotglob
# make dirs (missing old permission,acl,xattr data), and then mv the files
time find * -type d -exec mkdir -p "$dest"/{} \;
time find * -type f -exec mv {} "$dest"/{} \;
# also copy permissions, acls, xattrs
rsync -aAX "$src"/ "$dest"/
E torne-o executável:
chmod +rx supermove
E executá-lo
./supermove src/ dest/
E o resultado... antes:
$ find src dest
src/
src/d
src/d/f1
dest/
dest/d
dest/d/f2
Depois:
$ find src dest
src
src/d
dest
dest/d
dest/d/f1
dest/d/f2
Agora src/
devem ser apenas diretórios vazios. Se sim, você pode rm -r src
limpar.
Responder3
mv
as opções são todas sobre resolução de conflitos:
Escolha um:
-f force (always overwrite)
-i interactive (ask whether to overwrite)
-n no clobber (no overwrite)
E isso também é bom:
-v verbose
Caso contrário, os dados podem ser perdidos e/ou não ficará claro o que exatamente aconteceu.
mv também é superior no mesmo fs porque está apenas atualizando inodes de diretório, os arquivos não devem ser mexidos. A outra coisa é que quanto maior a operação, maior a chance de as coisas darem errado, como erros leves.