Qual é a melhor maneira de mesclar dois diretórios no mesmo sistema de arquivos no Linux?

Qual é a melhor maneira de mesclar dois diretórios no mesmo sistema de arquivos no Linux?

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, mvvá 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 rsyncwith --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 mvfalha. Aqui estão alguns dados de exemplo:

mkdir -p src/d dest/d
touch src/d/f1 dest/d/f2

Veja como mvfalha:

$ 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 echobefore 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 srclimpar.

Responder3

mvas 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.

informação relacionada