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 :-)find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1
para ignorar todos os nomes de arquivos (deve trabalhar com várias linhas)A soma de verificação precisa ter uma representação determinística e inequívoca dos arquivos como uma sequência. Determinístico significa que se você colocar os mesmos arquivos nos mesmos locais, obterá o mesmo resultado. Não ambíguo significa que dois conjuntos diferentes de arquivos têm representações diferentes.
Dados e metadados
Criar um arquivo contendo os arquivos é um bom começo. Essa é uma representação inequívoca (obviamente, pois você pode recuperar os arquivos extraindo o arquivo morto). Pode incluir metadados de arquivo, como datas e propriedade. No entanto, isso ainda não está certo: um arquivo é ambíguo, porque sua representação depende da ordem em que os arquivos são armazenados e, se aplicável, da compactação.
Uma solução é classificar os nomes dos arquivos antes de arquivá-los. Se os nomes dos seus arquivos não contiverem novas linhas, você poderá executá
find | sort
-las para listá-las e adicioná-las ao arquivo nesta ordem. Tome cuidado para informar ao arquivador para não recursar nos diretórios. Aqui estão alguns exemplos com POSIXpax
, GNU tar e cpio:Somente nomes e conteúdos, da maneira de baixa tecnologia
Se você quiser apenas levar em consideração os dados do arquivo e não os metadados, poderá criar um arquivo que inclua apenas o conteúdo do arquivo, mas não há ferramentas padrão para isso. Em vez de incluir o conteúdo do arquivo, você pode incluir o hash dos arquivos. Se os nomes dos arquivos não contiverem novas linhas e houver apenas arquivos e diretórios regulares (sem links simbólicos ou arquivos especiais), isso é bastante fácil, mas você precisa cuidar de algumas coisas:
Incluímos uma lista de diretórios além da lista de somas de verificação, caso contrário, diretórios vazios seriam invisíveis. A lista de arquivos é classificada (em um local específico e reproduzível - graças a Peter.O por me lembrar disso).
echo
separa as duas partes (sem isso, você pode criar alguns diretórios vazios cujo nome se parece com umamd5sum
saída que também pode passar para arquivos comuns). Também incluímos uma lista de tamanhos de arquivo, para evitar ataques de extensão .A propósito, o MD5 está obsoleto. Se estiver disponível, considere usar SHA-2, ou pelo menos SHA-1.
Nomes e dados, suportando novas linhas em nomes
Aqui está uma variante do código acima, que depende das ferramentas GNU para separar os nomes dos arquivos com bytes nulos. Isso permite que os nomes de arquivos contenham novas linhas. Os utilitários Digest GNU citam caracteres especiais em sua saída, para que não haja novas linhas ambíguas.
Uma abordagem mais robusta
Aqui está um script Python minimamente testado que cria um hash descrevendo uma hierarquia de arquivos. Leva os diretórios e o conteúdo do arquivo para as contas, ignora os links simbólicos e outros arquivos e retorna um erro fatal se algum arquivo não puder ser lido.
fonte
LC_ALL=C sort
para a verificação de ambientes diferentes ... (+ 1 btw)LC_ALL=C
é essencial se estiver sendo executado em várias máquinas e sistemas operacionais.cpio -o -
significa isso ? O cpio não usa stdin / out por padrão? Produz GNU cpio 2.12cpio: Too many arguments
Dê uma olhada no md5deep . Alguns dos recursos do md5deep que podem lhe interessar:
fonte
.../foo: Is a directory
que dá?md5deep -r -l -j0 . | md5sum
(onde-r
é recursivo,-l
significa "usar caminhos relativos", para que o caminho absoluto dos arquivos não interfira ao tentar comparar o conteúdo de dois diretórios, e-j0
significa usar 1 thread para evitar o não determinismo devido para md5sums individuais sendo retornados em ordens diferentes).Se seu objetivo é apenas encontrar diferenças entre dois diretórios, considere usar diff.
Tente o seguinte:
fonte
Você pode fazer o hash de todos os arquivos recursivamente e, em seguida, o texto resultante:
md5deep é necessário.
fonte
md5deep
usarhashdeep
no ubuntu 16.04 porque o pacote md5deep é apenas um manequim de transição para o hashdeep.## Invoked from: /home/myuser/dev/
qual é o seu caminho atual e## $ hashdeep -s -r -l ~/folder/
. Isso precisa ser ordenado, portanto o hash final será diferente se você alterar sua pasta ou linha de comando atual.Apenas conteúdo do arquivo , excluindo nomes de arquivos
Eu precisava de uma versão que apenas verificasse os nomes dos arquivos porque o conteúdo reside em diretórios diferentes.
Essa versão (resposta de Warren Young) ajudou muito, mas minha versão do
md5sum
resultado gera o nome do arquivo (relativo ao caminho do qual executei o comando) e os nomes das pastas eram diferentes, portanto, mesmo que as somas de verificação de arquivos individuais correspondam, a soma de verificação final não 't.Para corrigir isso, no meu caso, eu só precisava retirar o nome do arquivo de cada linha da
find
saída (selecione apenas a primeira palavra separada por espaços usandocut
):fonte
solução :
funciona solução rápida e mais fácil do que bash scripts.
consulte doc: https://pypi.python.org/pypi/checksumdir/1.0.5
fonte
nix-hash
do gerenciador de pacotes Nixfonte
Eu uso esse meu snippet para volumes moderados :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -
e este para XXXL :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -
fonte
-xdev
bandeira faz?man find
e ler esse manual bem;)-xdev Don't descend directories on other filesystems.
Uma boa soma de verificação de árvore é o ID da árvore do Git.
Infelizmente, não existe uma ferramenta autônoma disponível que possa fazer isso (pelo menos eu não o conheço), mas se você tem o Git à mão, pode apenas fingir configurar um novo repositório e adicionar os arquivos que deseja verificar no índice.
Isso permite que você produza o hash da árvore (reproduzível) - que inclui apenas conteúdo, nomes de arquivos e alguns modos de arquivo reduzidos (executável).
fonte
Como acompanhamento desta excelente resposta , se você deseja acelerar o cálculo da soma de verificação para um diretório grande, tente o GNU Parallel :
(Este está usando um Mac com
md5
, substitua conforme necessário.)O
-k
sinalizador é importante, que instruiparallel
a manter a ordem; caso contrário, a soma geral pode mudar de execução para execução, mesmo que os arquivos sejam iguais.-n 100
diz para executar cada instânciamd5
com 100 argumentos, este é um parâmetro que você pode ajustar para obter o melhor tempo de execução. Veja também-X
flag ofparallel
(embora no meu caso pessoal isso tenha causado um erro.)fonte
Um script que é bem testado e suporta várias operações, incluindo a localização de duplicatas, comparações de dados e metadados, mostrando adições, além de alterações e remoções, você pode gostar da Impressão digital .
A impressão digital no momento não produz uma única soma de verificação para um diretório, mas um arquivo de transcrição que inclui somas de verificação para todos os arquivos nesse diretório.
Isso será gerado
index.fingerprint
no diretório atual, que inclui somas de verificação, nomes de arquivos e tamanhos de arquivo. Por padrão, ele usa ambosMD5
eSHA1.256
.No futuro, espero adicionar suporte para Merkle Trees na impressão digital, o que fornecerá uma única soma de verificação de nível superior. No momento, você precisa reter esse arquivo para fazer a verificação.
fonte
Eu não queria novos executáveis nem soluções desajeitadas, então aqui está minha opinião:
fonte
Uma abordagem robusta e limpa
É isso que eu tenho em mente: qualquer um que tenha passado algum tempo trabalhando nisso praticamente pegaria outras pegadinhas e casos de canto.
Aqui está uma ferramenta (aviso: eu sou um colaborador). Dtreetrawl , muito leve na memória, que aborda a maioria dos casos, pode ser um pouco difícil, mas tem sido bastante útil.
Um exemplo de saída amigável para humanos:
fonte
Fazendo individualmente para todos os arquivos em cada diretório.
fonte
A migração para o formato de arquivo POSIX afeta as somas de verificação baseadas em Tar GNU
Esta resposta pretende ser uma atualização suplementar à abordagem do uso da saída Tar para misturar o conteúdo dos diretórios, como foi proposto (entre outras coisas) nas excelentes respostas de Warren Young e Gilles há algum tempo.
Desde então, pelo menos o openSUSE (desde seu lançamento 12.2) mudou o formato GNU Tar padrão de "GNU tar 1.13.x format" para o (ligeiramente) superior "formato POSIX 1003.1-2001 (pax)" superior ) . Também a montante (entre os desenvolvedores do GNU Tar) eles discutem para executar a mesma migração, veja, por exemplo, o último parágrafo desta página do manual do GNU Tar :
(Esta página também oferece uma boa revisão sobre os diferentes formatos de arquivo disponíveis no GNU Tar.)
No nosso caso, onde taramos o conteúdo do diretório e hash o resultado, e sem tomar medidas específicas, uma mudança do formato GNU para POSIX tem as seguintes conseqüências:
Apesar do conteúdo do diretório idêntico, a soma de verificação resultante será diferente.
Apesar do conteúdo do diretório idêntico, a soma de verificação resultante será diferente de execução para execução se os cabeçalhos pax padrão forem usados.
O último vem do fato de que o formato POSIX (pax) inclui cabeçalhos de pax estendidos, que são determinados por uma string de formato padrão
%d/PaxHeaders.%p/%f
no GNU Tar. Dentro dessa cadeia, o especificador%p
é substituído pelo ID do processo Tar gerado, o qual, obviamente, é diferente de execução para execução. Veja esta seção do manual GNU Tar e, em particular, esta para detalhes.Agora, datando de 28/03/2019, há um commit aceito upstream que desativa esse problema.
Portanto, para poder continuar usando o GNU Tar no caso de uso especificado, posso recomendar as seguintes opções alternativas:
Use a opção Tar
--format=gnu
para informar explicitamente o Tar para gerar o arquivo no formato "antigo". Isso é obrigatório para validar somas de verificação "antigas".Use o formato POSIX mais recente, mas especifique explicitamente um cabeçalho pax adequado, por exemplo, por
--pax-option="exthdr.name=%d/PaxHeaders/%f"
. No entanto, isso quebra a compatibilidade com versões anteriores às somas de verificação "antigas".Aqui está um fragmento de código Bash que eu uso regularmente para calcular somas de verificação do conteúdo do diretório, incluindo metadados:
Aqui,
<paths>
é substituído por uma lista separada por espaços dos caminhos de todos os diretórios que eu quero que sejam cobertos pela soma de verificação. O objetivo de usar o código de idioma C, a separação de bytes nulos de nomes de arquivos e o uso de localizar e classificar para obter uma ordem independente dos sistemas de arquivos dos arquivos no arquivo morto já é suficientemente discutido em outras respostas.Os parênteses circundantes mantêm a
LC_ALL
configuração local em um subshell.Além disso, uso a expressão
! -type s
comfind
para evitar avisos do Tar que ocorrem se os arquivos de soquete fizerem parte do conteúdo do diretório: O GNU Tar não arquiva soquetes. Se você preferir ser notificado sobre soquetes ignorados, deixe essa expressão de lado.Eu uso
--numeric-owner
com o Tar, para poder verificar as somas de verificação posteriormente, mesmo em sistemas, onde nem todos os proprietários de arquivos são conhecidos.A
--atime-preserve
opção para Tar é melhor omitida se alguma das<paths>
mentiras estiver em um dispositivo montado somente leitura. Caso contrário, você será avisado de cada arquivo cujo carimbo de data e hora de acesso Tar não pôde restaurar. Para a gravação ativada<paths>
, eu uso essa opção para preservar os carimbos de data e hora de acesso nos diretórios de hash.A opção Tar
--no-recursion
, que já foi usada na proposta de Gilles , impede que o Tar desça recursivamente nos diretórios por si só e, em vez disso, opere arquivo por arquivo no que for alimentado a partir dafind
saída classificada .E, finalmente, não é verdade que eu uso
md5sum
: eu realmente usosha256sum
.fonte
Se você não precisa do md5, pode tentar
fonte