web-dev-qa-db-fra.com

md5 tous les fichiers dans une arborescence de répertoires

J'ai un répertoire avec une structure comme ceci:

.
├── Test.txt
├── Test1
│   ├── Test1.txt
│   ├── Test1_copy.txt
│   └── Test1a
│       ├── Test1a.txt
│       └── Test1a_copy.txt
└── Test2
   ├── Test2.txt
   ├── Test2_copy.txt
   └── Test2a
       ├── Test2a.txt
       └── Test2a_copy.txt

Je voudrais créer un script bash qui fait une somme de contrôle md5 de chaque fichier de ce répertoire. Je veux pouvoir taper le nom du script dans la CLI, puis le chemin d'accès au répertoire que je veux hacher et le faire fonctionner. Je suis sûr qu'il existe de nombreuses façons d'y parvenir. Actuellement, j'ai:

#!/bin/bash

for file in "$1" ; do 
    md5 >> "${1}__checksums.md5"
done

Cela se bloque et cela ne fonctionne pas. Peut-être devrais-je utiliser find?

Une mise en garde - les répertoires que je veux hacher auront des fichiers avec des extensions différentes et peuvent ne pas toujours avoir exactement la même arborescence. Je veux aussi quelque chose qui fonctionne dans ces différentes situations.

15
Bleakley

En utilisant md5deep

md5deep -r path/to/dir > sums.md5

Utilisation de find et md5sum

find relative/path/to/dir -type f -exec md5sum {} + > sums.md5

Sachez que lorsque vous exécutez la vérification de vos sommes MD5 avec md5sum -c sums.md5, vous devez l'exécuter à partir du même répertoire à partir duquel vous avez généré sums.md5 fichier. En effet, find génère des chemins relatifs à votre emplacement actuel, qui sont ensuite placés dans sums.md5 fichier.

Si c'est un problème, vous pouvez faire relative/path/to/dir absolu (par exemple, en mettant $PWD/ devant votre chemin). De cette façon, vous pouvez exécuter la vérification sur sums.md5 depuis n'importe quel endroit. L'inconvénient est que maintenant sums.md5 contient des chemins absolus, ce qui l'agrandit.

Fonction complète utilisant find et md5sum

Vous pouvez mettre cette fonction sur votre .bashrc fichier (situé dans votre $HOME répertoire):

function md5sums {
  if [ "$#" -lt 1 ]; then
    echo -e "At least one parameter is expected\n" \
            "Usage: md5sums [OPTIONS] dir"
  else
    local OUTPUT="checksums.md5"
    local CHECK=false
    local MD5SUM_OPTIONS=""

    while [[ $# > 1 ]]; do
      local key="$1"
      case $key in
        -c|--check)
          CHECK=true
          ;;
        -o|--output)
          OUTPUT=$2
          shift
          ;;
        *)
          MD5SUM_OPTIONS="$MD5SUM_OPTIONS $1"
          ;;
      esac
      shift
    done
    local DIR=$1 

    if [ -d "$DIR" ]; then  # if $DIR directory exists
      cd $DIR  # change to $DIR directory
      if [ "$CHECK" = true ]; then  # if -c or --check option specified
        md5sum --check $MD5SUM_OPTIONS $OUTPUT  # check MD5 sums in $OUTPUT file
      else                          # else
        find . -type f ! -name "$OUTPUT" -exec md5sum $MD5SUM_OPTIONS {} + > $OUTPUT  # Calculate MD5 sums for files in current directory and subdirectories excluding $OUTPUT file and save result in $OUTPUT file
      fi
      cd - > /dev/null  # change to previous directory
    else
      cd $DIR  # if $DIR doesn't exists, change to it to generate localized error message
    fi
  fi
}

Après avoir exécuté source ~/.bashrc, vous pouvez utiliser md5sums comme la commande normale:

md5sums path/to/dir

va générer checksums.md5 fichier dans path/to/dir répertoire, contenant les sommes MD5 de tous les fichiers de ce répertoire et de ses sous-répertoires. Utilisation:

md5sums -c path/to/dir

pour vérifier les sommes de path/to/dir/checksums.md5 fichier.

Notez que path/to/dir peut être relatif ou absolu, md5sums fonctionnera bien dans les deux cas. Résultat checksums.md5 le fichier contient toujours des chemins relatifs à path/to/dir. Vous pouvez utiliser un nom de fichier différent, puis par défaut checksums.md5 en fournissant -o ou --output option. Toutes les options, autres que -c, --check, -o et --output sont passés à md5sum.

Première moitié de md5sums la définition de la fonction est responsable de l'analyse des options. Voir cette réponse pour plus d'informations à ce sujet. La seconde moitié contient des commentaires explicatifs.

27
TeWu

Que diriez-vous:

find /path/you/need -type f -exec md5sum {} \; > checksums.md5

pdate # 1: Amélioration de la commande basée sur la recommandation de @ twalberg pour gérer les espaces blancs dans les noms de fichiers.

Mise à jour # 2: Amélioré basé sur la suggestion de @ jil, pour supprimer les appels inutiles xargs et utiliser -exec option de recherche à la place.

Mise à jour # 3: @Blake une implémentation naïve de votre script ressemblerait à ceci:

#!/bin/bash
# Usage: checksumchecker.sh <path>
find "$1" -type f -exec md5sum {} \; > "$1"__checksums.md5
4
taskalman
#!/bin/bash
shopt -s globstar
md5sum "$1"/** > "${1}__checksums.md5"

Explication: shopt -s globstar(manuel) active ** joker glob récursif. Cela signifie que "$1"/** s'étendra à la liste de tous les fichiers récursivement sous le répertoire donné en paramètre $1. Ensuite, le script appelle simplement md5sum avec cette liste de fichiers comme paramètre et > "${1}__checksums.md5" redirige la sortie vers le fichier.

2
jil
md5deep -r $your_directory | awk {'print $1'} | sort | md5sum | awk {'print $1'}

Réponse mise à jour

Si vous aimez la réponse ci-dessous, ou l'une des autres, vous pouvez créer une fonction qui exécute la commande pour vous. Donc, pour le tester, tapez ce qui suit dans Terminal pour déclarer une fonction:

function sumthem(){ find "$1" -type f -print0 | parallel -0 -X md5 > checksums.md5; }

Ensuite, vous pouvez simplement utiliser:

sumthem /Users/somebody/somewhere

Si cela fonctionne comme vous le souhaitez, vous pouvez ajouter cette ligne à la fin de votre "profil bash" et la fonction sera déclarée et disponible à tout moment. connecté. Votre "profil bash" est probablement dans $HOME/.profile

Réponse originale

Pourquoi ne pas faire fonctionner tous vos cœurs de CPU en parallèle pour vous?

find . -type f -print0 | parallel -0 -X md5sum

Cela trouve tous les fichiers (-type f) dans le répertoire courant (.) et les affiche avec un octet nul à la fin. Ceux-ci sont ensuite passés passés dans GNU Parallel, qui est informé que les noms de fichiers se terminent par un octet nul (-0) et qu'il doit faire autant de fichiers que possible à la fois (-X) pour enregistrer la création d'un nouveau processus pour chaque fichier et il devrait md5sum les fichiers.

Cette approche paiera le plus gros bonus, en termes de vitesse, avec de grandes images comme des fichiers Photoshop.

1
Mark Setchell