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.