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 -ssó 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 -spor uma chamada para sort. O -k 2bit diz para pular o hash MD5, classificando apenas os nomes dos arquivos, que estão no campo 2 até o final da linha, pelo sortcá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 sortchamada. A find -svariante 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 lse tal, que silenciosamente classifica o conteúdo do diretório para você. findsem -sou uma sortchamada 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 md5sumcomandos para md5ou 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 sortadequadamente. Outra armadilha é que alguns programas de soma de dados não escrevem o nome de um arquivo, um excelente exemplo sendo o antigo sumprograma Unix .
Esse método é um pouco ineficiente, chamando md5sumN + 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 tarpara embalar o conteúdo do diretório e envie-o para md5sum:
$ tar -cf - somedir | md5sum
Como tartambé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 findmétodo baseado acima, tarele 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 | cpioopçã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 :-)