J'ai un répertoire avec plusieurs fichiers img et certains d'entre eux sont identiques mais ils ont tous des noms différents. J'ai besoin de supprimer les doublons mais sans outils externes uniquement avec un bash
script. Je suis débutant sous Linux. J'ai essayé la boucle imbriquée pour comparer les md5
sommes et selon le résultat, mais quelque chose ne va pas avec la syntaxe et cela ne fonctionne pas. de l'aide?
ce que j'ai essayé c'est ...
for i in directory_path; do
sum1='find $i -type f -iname "*.jpg" -exec md5sum '{}' \;'
for j in directory_path; do
sum2='find $j -type f -iname "*.jpg" -exec md5sum '{}' \;'
if test $sum1=$sum2 ; then rm $j ; fi
done
done
Je reçois: test: too many arguments
bash
shell-script
linuxbegin
la source
la source
Réponses:
Il y a pas mal de problèmes dans votre script.
Premièrement, afin d'assigner le résultat d'une commande à une variable, vous devez l'enfermer soit dans backtics (
`command`
), soit de préférence$(command)
. Vous l'avez entre guillemets simples ('command'
) qui, au lieu d'affecter le résultat de votre commande à votre variable, affecte la commande elle-même sous forme de chaîne. Par conséquent, voustest
êtes en fait:Le problème suivant est que la commande
md5sum
renvoie plus que le hachage:Vous souhaitez uniquement comparer le premier champ, vous devez donc analyser la
md5sum
sortie en la passant par une commande qui imprime uniquement le premier champ:ou
De plus, la
find
commande renverra de nombreuses correspondances, pas une seule et chacune de ces correspondances sera dupliquée par la secondefind
. Cela signifie qu'à un moment donné, vous comparerez le même fichier à lui-même, la somme md5 sera identique et vous finirez par supprimer tous vos fichiers (j'ai exécuté cela sur un répertoire de test contenanta.jpg
etb.jpg
):Vous ne voulez pas exécuter
for i in directory_path
sauf si vous passez un tableau de répertoires. Si tous ces fichiers sont dans le même répertoire, vous souhaitez exécuterfor i in $(find directory_path -iname "*.jpg"
) pour parcourir tous les fichiers.C'est une mauvaise idée d'utiliser des
for
boucles avec la sortie de find. Vous devez utiliser deswhile
boucles ou des globes :ou, si tous vos fichiers se trouvent dans le même répertoire:
Selon votre shell et les options que vous avez définies, vous pouvez utiliser la globalisation même pour les fichiers dans les sous-répertoires, mais n'abordons pas cela ici.
Enfin, vous devez également citer vos variables, sinon les chemins de répertoire avec des espaces briseront votre script.
Les noms de fichiers peuvent contenir des espaces, de nouvelles lignes, des barres obliques inverses et d'autres caractères étranges, pour les traiter correctement dans une
while
boucle, vous devrez ajouter quelques options supplémentaires. Ce que vous voulez écrire, c'est quelque chose comme:Une manière encore plus simple serait:
Une meilleure version qui peut gérer les espaces dans les noms de fichiers:
Ce petit script Perl passera par les résultats de la
find
commande (ie le md5sum et le nom du fichier). L'-a
option deperl
fractionnement des lignes d'entrée à l'espace blanc et les enregistre dans leF
tableau,$F[0]
sera donc le md5sum et$F[1]
le nom de fichier. Le md5sum est enregistré dans le hachagek
et le script vérifie si le hachage a déjà été vu (if $k{$F[0]}>1
) et supprime le fichier s'il a (system("rm $F[1]")
).Bien que cela fonctionne, cela sera très lent pour les grandes collections d'images et vous ne pouvez pas choisir les fichiers à conserver. Il existe de nombreux programmes qui gèrent cela de manière plus élégante, notamment:
fdupes
fslint
la source
unlink
au lieu de passer unsystem
appel.$F[1]
. Corrigé en utilisant des tranches de tableau. Quant à unlink () je sais, mais je voulais garder les perlismes au minimum et l'appel système est plus facile à comprendre si vous ne connaissez pas Perl.Il existe un programme astucieux appelé
fdupes
qui simplifie l'ensemble du processus et invite l'utilisateur à supprimer les doublons. Je pense que cela vaut la peine de vérifier:Fondamentalement, il m'a demandé quel fichier conserver , j'ai tapé 1 et il a supprimé le second.
D'autres options intéressantes sont:
D'après votre exemple, vous voudrez probablement l'exécuter en tant que:
Voir
man fdupes
pour toutes les options disponibles.la source