No bash, como eu comparo duas pastas para garantir que elas contenham os mesmos conjuntos de arquivos?

2

Eu copiei uma pasta massiva de uma máquina Windows para uma máquina Linux e, como alguns nomes de arquivos são muito grandes (e alguns outros erros que eu ignorei), alguns arquivos não puderam ser copiados. Atualmente estou executando diff -r entre as duas pastas para gerar uma lista dos arquivos que estão na pasta original, mas não na cópia. No entanto, até agora as únicas coisas que parece ter reconhecido são pastas ausentes, ou seja, parece estar ignorando arquivos. Existe uma maneira melhor de fazer essa comparação? Em particular, estou preocupado que o Bash simplesmente não consiga reconhecer esses arquivos com nomes de arquivo muito longos.

J. Min
fonte
Em geral, os sistemas de arquivos modernos do Linux lidam com nomes de arquivos mais longos, nomes de caminhos mais longos e aninhamento de pastas mais profundo do que o NTFS do Windows. Pode querer verificar a mensagem de erro que te lançou nesta estrada. Eu sei que o diff compara o conteúdo dos arquivos. Não tenho certeza se funciona em pastas do jeito que você está falando. SE é para perguntas e respostas. Uma pergunta melhor seria: "Como faço para comparar duas pastas para garantir que elas contenham os mesmos conjuntos de arquivos". Se você editar sua pergunta para refletir o que está tentando fazer, alguém provavelmente terá um trecho de código bash ou python para fazer exatamente isso.
Xalorous
Eu acabei de testar. diff -r faz mudanças de arquivo captura, mesmo dentro em subdiretórios. Você pode preferir usar -ur, no entanto. (Eu acho a saída muito mais inteligível dessa maneira.)
jpaugh

Respostas:

1

Você pode fazer algo não totalmente diferente:

(cd some/where; ls -lR) > somewhere.txt
(cd else/where; ls -lR) > elsewhere.txt
diff somewhere.txt elsewhere.txt

Eu não tentei isso, depende de metadados de arquivos (datas etc) sendo preservados ( cp -p ...) e na lsclassificação de nomes de arquivos na mesma ordem (o que deveria).

RedGrittyBrick
fonte
Desculpe, a notação some / where me deixou um pouco perdida. O que isso seria em termos de diretórios?
J. Min
somee elsee wheresão apenas espaços reservados para os caminhos relativos para as duas pastas pai que você deseja comparar (incluindo comparando seus subdiretórios). por exemplo cd /home/jmin/catpicse cd /home/jmin/copy_of_catpicsou o que for.
RedGrittyBrick
1

diff --recursive( -r) captura alterações de arquivo, mesmo dentro de subdiretórios.

Você pode preferir usar diff --unified --recursive, no entanto. Ele cria um diff unificado , que exibe linhas alteradas prefixadas com (+) para additon e (-) para remoção. Convenientemente, também exibe linhas circunvizinhas (ou seja, contexto ), para que você possa descobrir o que está acontecendo lá.

jpaugh
fonte
Eu vou correr isso agora. Espero que isso seja feito dentro de um prazo razoável. Só para ter certeza, é diff -ur ao contrário de diff -r, certo? ou seja, você não está me dizendo para executar algo como diff -r -ur?
J. Min
De volta de tentar, depois de 3 horas comecei a receber rajadas aleatórias de atraso no meu sistema. Na quarta hora eu não tive escolha a não ser desligar.
J. Min
Sim, eu quis dizer diff -u -r. Isso é louco! Você pode precisar de uma ferramenta que é otimizada para grandes conjuntos de arquivos, então. O rsync é provavelmente sua melhor aposta.
jpaugh
1

Se o rsync for uma opção viável, talvez o --itemize-changes(-i) e as --dry-runopções sejam úteis:

rsync -zaic src_dir/ dest_dir/ --dry-run

-z compacta arquivos durante a transferência, -a copia no modo de arquivo e -c baseia as comparações de arquivos em somas de verificação em vez de data de modificação ou tamanho.

-i listará os arquivos individuais que são diferentes e --dry-run significa que nenhum dado será transferido, apenas gerando uma lista.

sippybear
fonte
Isso é de uso? No meu conhecimento, o rsync exigiria a cópia dos arquivos novamente.
J. Min
1
@ J.Min a bandeira --dry-run realmente não copia nada, apenas mostra o que teria acontecido :)
sippybear
1
diff <(cd /first/path/ && find ./ | sort) <(cd /second/path/ && find ./ | sort)

Isso é semelhante a essa outra resposta, mas:

  • Estou usando findpara gerar listas de objetos (arquivos, diretórios); cabe aqui melhor do que lsporque sua saída contém apenas caminhos.
  • sortgarante que a ordem relativa dos objetos seja preservada, independentemente de em que ordem cada findlista.
  • A <(…)sintaxe evita arquivos temporários em bash.
  • findserá executado somente se o correspondente cdfor bem-sucedido, graças ao &&operador. Isso evitará que você execute findno diretório atual se houver um erro de digitação em qualquer caminho.

Notas Adicionais:

  • Os caminhos retornados por findserão relativos aos diretórios cdpara nós . Certifique-se /first/path/e /second/path/corresponda um ao outro.
  • Saída vazia diffindica que os dois diretórios são idênticos; mas lembre-se…
  • … O comando opera somente em caminhos, não verifica se o conteúdo ou metadados correspondem.
  • Nomes de objetos com caracteres incomuns (por exemplo, com novas linhas) irão quebrar a lógica.
Kamil Maciorowski
fonte
Você pode simplesmente usar sdiff -s, ao contrário diff, para mostrar apenas as diferenças das duas listas, ou seja, os arquivos que estão em um diretório e não no outro.
AnythingIsFine