O caminho certo depende exatamente do motivo pelo qual você está perguntando:
Opção 1: comparar apenas dados
Se você apenas precisar de um hash do conteúdo do arquivo da árvore, isso funcionará:
$ find -s somedir -type f -exec md5sum {} \; | md5sum
Isso primeiro resume todo o conteúdo do arquivo individualmente, em uma ordem previsível, depois passa a lista de nomes de arquivos e os hashes MD5 para serem separados por hash, fornecendo um valor único que muda apenas quando o conteúdo de um dos arquivos na árvore é alterado.
Infelizmente, find -s
só funciona com o BSD find (1), usado no macOS, FreeBSD, NetBSD e OpenBSD. Para obter algo comparável em um sistema com GNU ou SUS find (1), você precisa de algo um pouco mais feio:
$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum
Substituímos find -s
por uma chamada para sort
. O -k 2
bit diz para pular o hash MD5, classificando apenas os nomes dos arquivos, que estão no campo 2 até o final da linha, pelo sort
cálculo da conta.
Há uma fraqueza nessa versão do comando, que é susceptível de ficar confusa se você tiver algum nome de arquivo com novas linhas, porque parecerá várias linhas para a sort
chamada. A find -s
variante não tem esse problema, porque a travessia e a classificação da árvore acontecem dentro do mesmo programa find
,.
Em ambos os casos, a classificação é necessária para evitar falsos positivos: os sistemas de arquivos Unix / Linux mais comuns não mantêm as listas de diretórios em uma ordem estável e previsível. Você pode não perceber isso usando ls
e tal, que silenciosamente classifica o conteúdo do diretório para você. find
sem -s
ou uma sort
chamada imprimirá os arquivos na ordem em que o sistema de arquivos subjacente os retornar, o que fará com que esse comando dê um valor de hash alterado se a ordem dos arquivos fornecidos como entrada for alterada.
Pode ser necessário alterar os md5sum
comandos para md5
ou alguma outra função de hash. Se você escolher outra função de hash e precisar da segunda forma do comando para o seu sistema, poderá ser necessário ajustá-lo sort
adequadamente. Outra armadilha é que alguns programas de soma de dados não escrevem o nome de um arquivo, um excelente exemplo sendo o antigo sum
programa Unix .
Esse método é um pouco ineficiente, chamando md5sum
N + 1 vezes, em que N é o número de arquivos na árvore, mas esse é um custo necessário para evitar o hash de metadados de arquivos e diretórios.
Opção 2: comparar dados e metadados
Se você precisar detectar que alguma coisa em uma árvore mudou, não apenas o conteúdo do arquivo, peça tar
para embalar o conteúdo do diretório e envie-o para md5sum
:
$ tar -cf - somedir | md5sum
Como tar
também vê permissões de arquivos, propriedade etc., isso também detectará alterações nessas coisas, não apenas alterações no conteúdo do arquivo.
Esse método é consideravelmente mais rápido, pois faz apenas uma passagem pela árvore e executa o programa de hash apenas uma vez.
Como no find
método baseado acima, tar
ele processará os nomes de arquivos na ordem em que o sistema de arquivos subjacente os retorna. Pode ser que, no seu aplicativo, você tenha certeza de que não fará com que isso aconteça. Posso pensar em pelo menos três padrões de uso diferentes, onde é provável que seja esse o caso. (Não vou listá-los, porque estamos entrando em território de comportamento não especificado. Cada sistema de arquivos pode ser diferente aqui, mesmo de uma versão do sistema operacional para a próxima.)
Se você se encontrar com falsos positivos, recomendo ir com a find | cpio
opção na resposta de Gilles .
find .
vez defind somedir
. Dessa forma, os nomes dos arquivos são os mesmos ao fornecer diferentes especificações de caminho a serem encontradas; isso pode ser complicado :-)