
Preciso encontrar todos os arquivos que existem em qualquer lugar do dir1
, mas não existem em nenhum lugar do dir2
. dir1
e dir2
pode ter estrutura diferente, por isso diff -r
não funciona bem.
Responder1
Tente fazer uma lista de arquivos sem caminho. Dessa forma, você pode comparar dois diretórios. No entanto, os nomes dos arquivos devem ser todos diferentes. Se você tiver o mesmo nome de arquivo repetido em dir1 em subdiretórios diferentes, a remoção do caminho removerá a exclusividade do nome do arquivo. Você pode obter uma lista de cada diretório sem nomes de caminho como este:
find dir1/ -exec basename {} \; | sort
find dir2/ -exec basename {} \; | sort
Todos juntos seriam algo assim
diff <(find dir1/ -exec basename {} \; | sort) <(find dir2/ -exec basename {} \; | sort)
Vejo que há um comentário sugerindo o uso de fdupes. fdupes
se definitivamente uma solução melhor.
Responder2
Um método bruto poderia estar usando md5sum
. Esteja ciente de que arquivos com comprimento zero sempre serão vistos como duplicados, portanto, você pode querer find
apenas arquivos com tamanho de pelo menos um byte.
find /first/path -type f -exec md5sum -b \{\} \; > /tmp/md5-path1.txt
cut -b1-32 < /tmp/md5-path1-short.txt
find /second/path -type f -exec md5sum -b \{\} \; > /tmp/md5-path2.txt
cut -b1-32 < /tmp/md5-path2-short.txt
Arquivos no caminho1 que não estão no caminho2 (remova a opção '-v'
grep /tmp/md5-path1.txt -v -F -f /tmp/md5/path2-short.txt
Nível CYA: profissional
O 32 acima ocorre porque os hashes MD5 têm 32 bytes de comprimento. Se você usasse, digamos, sha1sum
, que tem uma chance ainda menor de colisões, usaria um comprimento de 40; sha224sum
requer 56, sha256sum
requer 64 e sha512sum
128.
Nível CYA: paranóico
Isto pode não funcionar em alguns esquemas de cache nos quais os metadados são mantidos em arquivoscujo nome contém o hash do arquivo original.
(isso realmente aconteceu comigo com uma instalação do Wordpress + Magento anos atrás, onde queríamos migrar um enorme cache de artigos enquanto removíamos entradas obsoletas).
Nesse caso você teria que usar um esquema de hash diferente - solução rápida - para evitar grep
retornar falsos positivos, confundindo a entrada de metadados com o arquivo original (portanto, use SHA1 se o cache usar MD5 ou vice-versa); ou usar sed
para reescrever todas as linhas nos arquivos "curtos" para adicionar um "^" no início, transformando-o em um regex ancorado e removendo o -F
sinalizador de grep
para processar o arquivo como regexes em vez de strings simples.
Responder3
Então, a solução parcial que encontrei é:
find dir1 -type f | grep -vxFf <(fdupes -r dir1 dir2)
mas digo "parcial", porque se houver duplicatas em dir1
, elas não serão mostradas, então você precisa executar fdupes -r dir1
primeiro.