Esta solução encontrará duplicatas no tempo O (n). Cada arquivo tem uma soma de verificação gerada para ele, e cada arquivo, por sua vez, é comparado ao conjunto de checksums conhecidos por meio de um array associativo.
#!/bin/bash
#
# Usage: ./delete-duplicates.sh [<files...>]
#
declare -A filecksums
# No args, use files in current directory
test 0 -eq $# && set -- *
for file in "$@"
do
# Files only (also no symlinks)
[[ -f "$file" ]] && [[ ! -h "$file" ]] || continue
# Generate the checksum
cksum=$(cksum <"$file" | tr ' ' _)
# Have we already got this one?
if [[ -n "${filecksums[$cksum]}" ]] && [[ "${filecksums[$cksum]}" != "$file" ]]
then
echo "Found '$file' is a duplicate of '${filecksums[$cksum]}'" >&2
echo rm -f "$file"
else
filecksums[$cksum]="$file"
fi
done
Se você não especificar nenhum arquivo (ou curinga) na linha de comando, ele usará o conjunto de arquivos no diretório atual. Ele irá comparar arquivos em vários diretórios, mas não é escrito para recorrer aos próprios diretórios.
O "primeiro" arquivo do conjunto é sempre considerado a versão definitiva. Nenhuma consideração é tomada em relação a tempos de arquivo, permissões ou propriedades. Apenas o conteúdo é considerado.
Remova o echo
da linha rm -f "$file"
quando tiver certeza de que faz o que deseja. Observe que, se você substituir essa linha por ln -f "${filecksums[$cksum]}" "$file"
, poderá vincular o conteúdo com dificuldade. Mesmo salvando em espaço em disco, mas você não perderia os nomes dos arquivos.