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.
md5deep
md5deep -r path/to/dir > sums.md5
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.
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.
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
#!/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.
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.