Renomeie arquivos com caracteres aleatórios de sha1sum. Os nomes serão únicos?

2

Estou usando esse comando para renomear arquivos com caracteres aleatórios de sha1sum e mover todos os arquivos dos subdiretórios para o diretório atual:

for fname in 'find . -type f'; do mv "$fname" $(echo "$fname" | sha1sum | cut -f1 -d' ').html; done
  1. Mas a pergunta é: ele cria nomes de arquivos exclusivos? Estou preocupado com o gerado nome de sha1sum pode não ser exclusivo (gerado duas vezes ou mais).
  2. Se eu executar o comando acima e depois executar outro em outro diretório, ele gera um nome de arquivo exclusivo para cada arquivo?
por Najib-botak Chin 19.08.2011 / 09:32

3 respostas

2
As saídas

sha1sum serão únicas, desde que as entradas sejam únicas. (A não ser que você seja muito infeliz e tenha encontrado sha1sum colisão).

Quanto ao seu caso de uso: é um bom hábito usar printf '%s' "$fname" em vez de echo "$fname" , o primeiro funcionará quando $fname for -n ou -e ,… Consulte também enzotib remark , perdi isso em primeira vista.

Além disso, não sei exatamente quais são suas motivações, mas você pode considerar a alimentação de sha1sum com o conteúdo do arquivo em vez de nomes de arquivo. Dessa forma, você obteria um nome de arquivo exclusivo para cada conteúdo exclusivo.

    
por 19.08.2011 / 10:04
2

Primeiro, alguns assuntos sobre shell:

  • Não use for fname in 'find …' , pois isso irá manchar nomes de arquivos e falhará (porque a linha de comando é muito longa) se houver muitos arquivos com nomes muito longos. Use find -exec em vez disso. Como você precisa de expansão de shell no comando executado por find , invoca um shell .
  • Você precisa de aspas duplas em torno das substituições de comandos, bem como das substituições de variáveis ( "$fname" , "$(echo …)" ).
  • echo maneja barras invertidas em alguns shells (ele também manipula alguns argumentos que começam com - , mas isso não é um problema aqui, pois todos os argumentos começarão com ./ ). Uma maneira de imprimir qualquer string é literalmente printf "%s\n" "$fname" ou printf "%s" "$ fname" para evitar uma nova linha final. Aqui não vejo razão para pegar o hash do nome do arquivo mais uma nova linha final em oposição ao hash do nome do arquivo.

Então, recebemos este comando:

find . -type f -exec sh -c 'mv "$0" "$(printf "%s" "$0" | sha1sum | cut -f1 -d" ").html' {} \;

Será um pouco mais rápido invocar um shell para um lote inteiro de nomes de uma só vez.

find . -type f -exec sh -c 'for fname; do mv "$fname" "$(printf "%s" "$fname" | sha1sum | cut -f1 -d" ").html; done' _ {} +

Um problema com esse método é que, se mv começar a agir antes que find tenha terminado de percorrer o diretório, os arquivos que foram movidos poderão ser selecionados por mv . Isso não é um problema com seu comando porque ele aguarda que find termine antes de começar a mover os arquivos. Portanto, coloque os arquivos renomeados em uma hierarquia de diretórios diferente. Isso resolverá outro problema que seu comando proposto também possui, que é que mv pode sobrescrever um arquivo existente que por acaso é chamado <sha1sum>.html .

mkdir ../staging
find . -type f -exec sh -c 'for fname; do mv "$fname" ../staging/"$(printf "%s" "$fname" | sha1sum | cut -f1 -d" ").html; done' _ {} +
find . -depth \! -name "." -type d -exec rmdir {} +
mv ../staging/* .

Agora, vá para sua pergunta principal: dois arquivos com caminhos diferentes serão mapeados para dois hashes SHA-1 diferentes. Matematicamente falando, existem strings distintas com hashes SHA-1 idênticos (isso é óbvio, já que existem infinitas cadeias de caracteres, mas apenas finamente muitos hashes). No entanto, praticamente ninguém sabe como encontrá-los: não há colisão conhecida para o SHA-1. É possível que um dia no futuro o SHA-1 seja quebrado, caso em que seu procedimento estará seguro apenas contra colisões acidentais, não contra invasores mal-intencionados. Se isso acontecer (não em breve), você deve atualizar para o que for considerado um algoritmo hash seguro no momento.

Quanto à sua segunda pergunta: o hash é totalmente determinado pela string hash. Portanto, se você tiver dois arquivos chamados tweedledum/staple e tweedledee/staple e executar esse procedimento de renomeação a partir de cada diretório tweedledee e tweedledum , os dois diretórios acabarão com um arquivo chamado 1c0ee9c1eed005a476403c7651b739ae5bc7cf2a.html . Se você deseja ter nomes diferentes, é necessário colocar algum conteúdo diferenciado no texto com hash, como o nome do diretório.

    
por 19.08.2011 / 15:11
1

Antes de tudo, sugiro substituir

for fname in 'find . -type f'; do

com

find . -type f | while read -r fname; do

A seguir, com relação ao sha1sum, ele deve ser "virtualmente" exclusivo, o que significa que a probabilidade de ter arquivos diferentes com a mesma soma de verificação é consideravelmente baixa, de modo que você possa seguramente assumir que ele é único.

    
por 19.08.2011 / 10:04