Synology/Linux : comparaison de fichiers par nom, taille, checksum (MD5)

Je possède quelques NAS Synology et fais malheureusement parti de ceux qui plus ils ont de place plus ils stockent (de bordel). Du coup afin de libérer un peu de place j’ai entrepris de fouiller dans mes films de vacances histoire de voir si j’en ai en double voire triple exemplaires.

En effet entre les différents nommages de fichiers à la source, les logiciels qui renomment, ou non, ma manie de cliquer un peu partout, d’utiliser différents outils de DL etc, ça devient un bon gros boxon et je vois assez souvent Kodi me lister au moins 2 versions d’un même film.

Du coup, vu mon espace de stockage, j’avais 2 solutions :

  • Poser 1 semaine de congés pour ne faire que çà,
  • L’automatiser, en partie du moins. J’ai retenu cette solution  \o/

 

J’ai trouvé un script réalisé par Vermaden, pour Linux, BSD et Sun, qui permet de comparer (lister et/ou effacer) des fichiers par nom, taille et checksum (MD5).

Je l’ai juste modifié au niveau de la description afin de la mettre en français et d’y ajouter une note pour le rendre très facilement compatible avec un NAS Synology. Ces NAS sont basés sur Linux mais ne comportent pas tous les logiciels d’une distribution normale, entre autre ils n’ont pas md5sum mais cksum.

 

Fonctionnement

Selon l’option choisie il va se contenter de lister les fichiers similaires ou alors afficher aussi une commande pour supprimer les doublons.

  • -n : comparaison par nom (rapide)
  • -s comparaison par taille (normale)
  • -m comparaison par checkum (lent voire très lent)
  • -N, -S, -M idem que les autres mais avec instructions pour effacer les fichiers

Ensuite il suffit simple d’indiquer au script sur quel dossier s’exécuter /home ou /mnt/images pour par exemple viser un dossier d’images monté en local. Du coup ça vous donnera une commande de ce type DupCheck.sh -n /mnt/images pour comparer les images par leurs noms.

 

Exécution sur PC/serveur

Il suffit de créer un fichier script, par exemple DupCheck.sh et d’y coller le code. Puis lancer la commande avec l’option désirée sur le dossier cible, comme vu au-dessus.

 

Exécution sur Synology

Il faut déposer le script sur le NAS ou alors le créer directement dessus via l’outil Editeur de texte. Il faut bien entendu nommer le fichier en .sh afin qu’il soit reconnu comme un script. Il convient de changer une variable dedans, ligne 51, MD5="md5sum" devant devenir MD5="cksum" pour une question de compatibilité.

Et il peut ensuite être exécuté sur le NAS depuis un PC via SSH ou directement depuis le NAS par exemple via WebConsole.

 

Source

#! /bin/sh

# find duplicated files in directory tree
# comparing by file NAME, SIZE or MD5 checksum
# --------------------------------------------
# LICENSE(s): BSD / CDDL
# --------------------------------------------
# vermaden [AT] interia [DOT] pl
# http://strony.toya.net.pl/~vermaden/links.htm
#
# French Translation & Synology tip by Aerya
# https://upandclear.org/

__usage() {
  echo "**Script de comparaison de fichiers dans un même dossier**"
  echo ""
  echo "Utilisation : $( basename ${0} ) OPTION DOSSIER"
  echo ""
  echo "Options :   -n   (Rapide)  par nom"
  echo "            -s   (Normale) par taille"
  echo "            -m   (Lente)   par signature (https://fr.wikipedia.org/wiki/MD5)" 
  echo "            -N             '-n' mais avec instructions pour effacer"
  echo "            -S             '-s' mais avec instructions pour effacer"
  echo "            -M             '-m' mais avec instructions pour effacer"
  echo ""
  echo "Exemple : $( basename ${0} ) -s /home"
  echo ""
  echo "Pour s'en servir sur Synology, si vous ne voulez pas y installer MD5SUM, éditez le script et mettez 'MD5="cksum"' à la place de 'MD5="md5sum"' ligne 42"
  echo ""
  exit 1
  }

__prefix() {
  case $( id -u ) in
    (0) PREFIX="rm -rf" ;;
    (*) case $( uname ) in
          (SunOS) PREFIX="pfexec rm -rf" ;;
          (*)     PREFIX="sudo rm -rf"   ;;
        esac
        ;;
  esac
  }

__crossplatform() {
  case $( uname ) in
    (FreeBSD)
      MD5="md5 -r"
      STAT="stat -f %z"
      ;;
    (Linux)
      MD5="md5sum"
      STAT="stat -c %s"
      ;;
    (SunOS)
      echo "INFO: supported systems: FreeBSD Linux"
      echo
      echo "Porting to Solaris/OpenSolaris"
      echo "  -- provide values for MD5/STAT in '$( basename ${0} ):__crossplatform()'"
      echo "  -- use digest(1) instead for md5 sum calculation"
      echo "       $ digest -a md5 file"
      echo "  -- pfexec(1) is already used in '$( basename ${0} ):__prefix()'"
      echo
      exit 1
    (*)
      echo "INFO: supported systems: FreeBSD Linux"
      exit 1
      ;;
  esac
  }

__md5() {
  __crossplatform
  :> ${DUPLICATES_FILE}
  DATA=$( find "${1}" -type f -exec ${MD5} {} ';' | sort -n )
  echo "${DATA}" \
    | awk '{print $1}' \
    | uniq -c \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && continue
        SUM=$( echo ${LINE} | awk '{print $2}' )
        echo "${DATA}" | grep ${SUM} >> ${DUPLICATES_FILE}
      done

  echo "${DATA}" \
    | awk '{print $1}' \
    | sort -n \
    | uniq -c \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && continue
        SUM=$( echo ${LINE} | awk '{print $2}' )
        echo "count: ${COUNT} | md5: ${SUM}"
        grep ${SUM} ${DUPLICATES_FILE} \
          | cut -d ' ' -f 2-10000 2> /dev/null \
          | while read LINE
            do
              if [ -n "${PREFIX}" ]
              then
                echo "  ${PREFIX} \"${LINE}\""
              else
                echo "  ${LINE}"
              fi
            done
        echo
      done
  rm -rf ${DUPLICATES_FILE}
  }

__size() {
  __crossplatform
  find "${1}" -type f -exec ${STAT} {} ';' \
    | sort -n \
    | uniq -c \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && continue
        SIZE=$( echo ${LINE} | awk '{print $2}' )
        SIZE_KB=$( echo ${SIZE} / 1024 | bc )
        echo "count: ${COUNT} | size: ${SIZE_KB}KB (${SIZE} bytes)"
        if [ -n "${PREFIX}" ]
        then
          find ${1} -type f -size ${SIZE}c -exec echo "  ${PREFIX} \"{}\"" ';'
        else
          # find ${1} -type f -size ${SIZE}c -exec echo "  {}  " ';'  -exec du -h "  {}" ';'
          find ${1} -type f -size ${SIZE}c -exec echo "  {}  " ';'
        fi
        echo
      done
  }

__file() {
  __crossplatform
  find "${1}" -type f \
    | xargs -n 1 basename 2> /dev/null \
    | tr '[A-Z]' '[a-z]' \
    | sort -n \
    | uniq -c \
    | sort -n -r \
    | while read LINE
      do
        COUNT=$( echo ${LINE} | awk '{print $1}' )
        [ ${COUNT} -eq 1 ] && break
        FILE=$( echo ${LINE} | cut -d ' ' -f 2-10000 2> /dev/null )
        echo "count: ${COUNT} | file: ${FILE}"
        FILE=$( echo ${FILE} | sed -e s/'\['/'\\\['/g -e s/'\]'/'\\\]'/g )
        if [ -n "${PREFIX}" ]
        then
          find ${1} -iname "${FILE}" -exec echo "  ${PREFIX} \"{}\"" ';'
        else
          find ${1} -iname "${FILE}" -exec echo "  {}" ';'
        fi
        echo
      done 
  }

# main()

[ ${#} -ne 2  ] && __usage
[ ! -d "${2}" ] && __usage

DUPLICATES_FILE="/tmp/$( basename ${0} )_DUPLICATES_FILE.tmp"

case ${1} in
  (-n)           __file "${2}" ;;
  (-m)           __md5  "${2}" ;;
  (-s)           __size "${2}" ;;
  (-N) __prefix; __file "${2}" ;;
  (-M) __prefix; __md5  "${2}" ;;
  (-S) __prefix; __size "${2}" ;;
  (*)  __usage ;;
esac

 

(1 056 vues)

9
Poster un Commentaire

4 Fils de commentaires
5 Réponses de fil
2 Abonnés
 
Commentaire avec le plus de réactions
Le plus populaire des commentaires
5 Auteurs du commentaire
  S’abonner  
Notifier de
teddy

C’est exactement ce que je cherchais, je vais tester ça. Merci. :)

Franck M

Salut, ton petit script est excellent, l’usage est très pratique. Je cherchais justement un moyen de me débarrasser des doublons.

Je ne l’ai pas encore utilisé mais prend il en compte les sous-dossiers et peut-on faire des recherches avec -s et -N ?

Du genre, fichier du même nom et même poids à la poubelle.

Cordialement
Franck

jsonline

51, pas 42 la ligne du chksum. Je vais tester votre script.

jsonline

Mon DS411 m’a renvoyé l’erreur suivante : line 122: bc: command not found