Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 14/06/2009, à 23:52

BorX

Script Shell qui transforme les fichiers doublons en liens durs

Salut,

Ce script cherche les doublons dans les répertoires qu'on lui spécifie, et les remplace par des liens durs (hard links).

Les liens durs, c'est quoi
Un hardlink, c'est par exemple plusieurs fichiers qui pointent au même endroit du disque dur. Modifier l'un modifie tous les autres. Supprimer l'un ne change rien aux autres (contrairement aux liens symboliques avec lesquels la suppression de la cible rend le lien inutilisable).
Tous les fichiers liés pointent sur le même i-noeud de la partition, ils n'occupent donc que la place d'un seul de ces fichiers sur le disque. Chaque fichier reste cependant un fichier réél.
Attention : Lier des fichiers en dur ne peut être effectué que sur une même partition.

Ce script utilise fdupes qui permet de rechercher les doublons, mais ne permet pas de les lier ensuite.

Ainsi, lorsqu'on a par exemple besoin de place et qu'on n'a pas envie de chercher quels doublons supprimer, lier les doublons entre eux fait qu'ils prennent moins de place sur le disque dur (n fichiers doublons prennent la place d'un seul fichier) tout en gardant leur présence (supprimer l'un ne supprime pas les autres).
Ce système peut se montrer utile dans d'autres cas de figures, mais ça devient un autre sujet tongue

$ link_doublons.sh
Usage: link_doublons.sh [-v] [--exec | --noexec] [--taille taille] rep [ rep ... ]
  Cherche les doublons dans les répertoires qu'on lui spécifie, et les remplace par des liens durs (hard links).
  [-v]
     Mode verbeux (désactivé par défaut)
  [--exec | --noexec]
      Exécute le script de liaison des doublons sans poser la question
      N'exécute pas le script de liaison des doublons sans poser la question
  [--taille taille]
      Spécifie la taille des doublons à lier
      Par exemple :
        1  : Doublons dont la taille est d'au-moins   1 octet
        2  : Doublons dont la taille est d'au-moins  10 octets
        3  : Doublons dont la taille est d'au-moins 100 octets
        4  : Doublons dont la taille est d'au-moins   1 ko
        7  : Doublons dont la taille est d'au-moins   1 Mo (défaut)
        10 : Doublons dont la taille est d'au-moins   1 Go
  rep
      Répertoire dans lequel chercher les doublons à lier
  [ rep ... ]
      Répertoires supplémentaires dans lesquels chercher les doublons à lier

Ce script commence donc par rechercher les doublons avec fdupes dans les répertoires qu'on lui donne.
Il génère alors, dans le répertoire courant, un fichier yymmjj-HHMM-fdupes.log qui contient le résultat de la commande.

Il se base alors sur ce fichier pour générer un script shell, yymmjj-HHMM-link_doublons.sh, permettant de lier les doublons entre eux.

Une fois le script shell généré, il demande s'il doit être exécuté (à moins que l'une des options exec ou noexec n'ait été activée).

Par défaut, il ne cherche que les doublons dont la taille est supérieure ou égale à 1000000 octets (1Mo), à moins que l'option taille ne soit utilisée.

Enfin, le script est par défaut silencieux. On peut le faire causer davantage en activant le mode verbeux.

En exemple :
Les fichiers abc, abc2, abc3 sont ici identiques. Idem pour les fichiers defghij, defghij2, defghij3, defghij4.

$ find -type f -ls
701933    4 -rw-------   1 borx     borx            8 juin 15 00:18 ./rep2/rep4/defghij4
701931    4 -rw-------   1 borx     borx            8 juin 15 00:18 ./rep2/defghij2
701836    4 -rw-------   1 borx     borx            4 juin 15 00:18 ./rep2/abc2
701912    4 -rw-------   1 borx     borx            8 juin 15 00:18 ./rep1/defghij
701831    4 -rw-------   1 borx     borx            4 juin 15 00:17 ./rep1/abc
701932    4 -rw-------   1 borx     borx            8 juin 15 00:18 ./rep1/rep3/defghij3
701911    4 -rw-------   1 borx     borx            4 juin 15 00:18 ./rep1/rep3/abc3

$ du -sb .
20524	.

Je lance le script avec ses paramètres par défaut sur le répertoire en question.

$ link_doublons.sh .
Aucun doublon à lier trouvé

Bah oui, la taille des doublons recherchés est trop grande pour mes tous petits fichiers d'exemple tongue.

$ link_doublons.sh --taille 1 .
Lancer la liaison des doublons ? (y/Y/o/O/n/N)

Les options exec ou noexec auraient pu répondre elles-mêmes à la question posée.
Mais avant de répondre à la question, voyons les 2 fichiers créés par le script :

$ more 090615-0027-fdupes.log
Résultat de la commande fdupes -rnS .
4 bytes each:
./rep1/abc
./rep2/abc2
./rep1/rep3/abc3

8 bytes each:
./rep1/defghij
./rep2/defghij2
./rep1/rep3/defghij3
./rep2/rep4/defghij4

$ more 090615-0027-link_doublons.sh
#!/bin/bash

ln -fv "./rep1/abc" "./rep2/abc2"
ln -fv "./rep1/abc" "./rep1/rep3/abc3"

ln -fv "./rep1/defghij" "./rep2/defghij2"
ln -fv "./rep1/defghij" "./rep1/rep3/defghij3"
ln -fv "./rep1/defghij" "./rep2/rep4/defghij4"

On répondant oui à la question, le script ci-dessus est lancé, sinon on peut le garder pour plus tard, et dans tous les cas, ça laisse une trace de ce qui a été fait...

Après avoir répondu oui :

$ find -type f -ls
701937    4 -rwx------   1 borx     borx          224 juin 15 00:27 ./090615-0027-link_doublons.sh
701935    4 -rw-------   1 borx     borx          182 juin 15 00:25 ./090615-0027-fdupes.log
701912    4 -rw-------   4 borx     borx            8 juin 15 00:18 ./rep1/defghij
701912    4 -rw-------   4 borx     borx            8 juin 15 00:18 ./rep2/defghij2
701912    4 -rw-------   4 borx     borx            8 juin 15 00:18 ./rep1/rep3/defghij3
701912    4 -rw-------   4 borx     borx            8 juin 15 00:18 ./rep2/rep4/defghij4
701831    4 -rw-------   3 borx     borx            4 juin 15 00:17 ./rep1/abc
701831    4 -rw-------   3 borx     borx            4 juin 15 00:17 ./rep2/abc2
701831    4 -rw-------   3 borx     borx            4 juin 15 00:17 ./rep1/rep3/abc3

$ du -sb .
20898	.
$ rm 090615-0042-*
$ du -sb .
20492	.

Le résultat n'a pratiquement pas changé. Les fichiers sont toujours là, et font toujours la même taille, sauf qu'ils pointent désormais tous vers le même i-noeud que leurs doublons et qu'ils occupent donc désormais moins de place...


Le script :

#!/bin/bash

# Fonctions globales
###############################################################################

# Affiche les paramètres sur la sortie standard si le mode verbeux est activé
displayInfo() {
	$VERBOSE && cat <<EOF
$*
EOF
	return 0
}

# Affiche les paramètres sur la sortie d'erreur
displayError() {
	cat >&2 <<EOF
$*
EOF
	return 0
}

# Arrête l'exécution du script avec un certain code retour et en affichant
# préalablement un message sur la sortie d'erreur
throwError() {
	RETURN_VALUE=$1
	shift
	displayError "$*"
	exit $RETURN_VALUE
}

# Affiche sur la sortie d'erreur le mode d'usage du script
usage() {
	throwError 1 \
"Usage: $0 [-v] [--exec | --noexec] [--taille taille] rep [ rep ... ]
  Cherche les doublons dans les répertoires qu'on lui spécifie, et les remplace par des liens durs (hard links).
  [-v]
     Mode verbeux (désactivé par défaut)
  [--exec | --noexec]
      Exécute le script de liaison des doublons sans poser la question
      N'exécute pas le script de liaison des doublons sans poser la question
  [--taille taille]
      Spécifie la taille des doublons à lier
      Par exemple :
        1  : Doublons dont la taille est d'au-moins   1 octet
        2  : Doublons dont la taille est d'au-moins  10 octets
        3  : Doublons dont la taille est d'au-moins 100 octets
        4  : Doublons dont la taille est d'au-moins   1 ko
        7  : Doublons dont la taille est d'au-moins   1 Mo (défaut)
        10 : Doublons dont la taille est d'au-moins   1 Go
  rep
      Répertoire dans lequel chercher les doublons à lier
  [ rep ... ]
      Répertoires supplémentaires dans lesquels chercher les doublons à lier"
}


# Fonctions spécifiques
###############################################################################

recherche_doublon() {
	# On recherche des doublons dans les répertoires fournis
	displayInfo "Recherche des doublons (Résultats dans $fdupes_log)"
	echo "Résultat de la commande fdupes -rnS $*" > $fdupes_log
	$VERBOSE || quiet='q'
	fdupes -rnS$quiet $* >> $fdupes_log
	return $?
}

construire_script() {
	# On initialise le script shell de sortie
	displayInfo "Création du script $link_doublons_sh"
	echo -e '#!/bin/bash\n' > $link_doublons_sh
	chmod u+x $link_doublons_sh

	ignore=true
	i=0

	# On parcourt chaque ligne du résultat du fdupes
	while read ligne; do
		# Si la ligne commence par un nombre de n chiffres
		if echo $ligne | grep -Eq "^[0-9]{$taille}.* byte.* each:$"; then
			# Alors on n'ignorera pas les lignes qui suivront
			ignore=false
		# Pour chaque ligne à ne pas ignorer
		elif [ "$ignore" == "false" ]; then
			# Si la ligne n'est pas vide
			if [ -n "$ligne" ]; then
				# On garde le nom du fichier dans un tableau
				fic[$i]="$ligne"
				i=$(($i + 1))
			# Dès qu'on rencontre une ligne vide
			else
				# On lie le premier élément du tableau vers le deuxième
				# puis vers le troisième, puis vers le quatrième, ...
				for j in $(seq 1 $(($i - 1))); do
					echo "ln -fv \"${fic[0]}\" \"${fic[$j]}\"" >> $link_doublons_sh
				done
				echo "" >> $link_doublons_sh
				# On remet les compteurs à zéro, et on recommence
				unset fic
				i=0
				ignore=true
			fi
		fi
	done < "$fdupes_log"
}


# Vérification des dépendances
###############################################################################
which fdupes >/dev/null 2>&1 || throwError 4 "Fonctionnement impossible sans fdupes"


# Initialisation des paramètres avec les valeurs par défaut
###############################################################################

# Mode verbeux (désactivé par défaut)
VERBOSE=false

# Taille des doublons à lier
taille=7

# Lancement automatique du script
lancerScriptLiaison=


# Initialisation des paramètres en fonction des saisies utilisateurs
###############################################################################

# Récupération des paramètres
TEMP=$(getopt -o v --long exec,noexec,taille: -n "$0" -- "$@")
[ $? != 0 ] && usage
eval set -- "$TEMP"

# Traitement des paramètres
while true ; do
        case "$1" in
                --exec)   lancerScriptLiaison='y'; shift;;
                --noexec) lancerScriptLiaison='n'; shift;;
                --taille) taille=$2;               shift 2;;
                -v)       VERBOSE=true;            shift;;
                --) shift; break;;
                *) usage;;
        esac
done


# Contrôle des paramètres
###############################################################################

# Si aucun argument fourni alors arrêt du script avec affichage du mode d'usage
[ -z "$1" ] && usage

# Contrôle des paramètres numériques
[ $taille -gt 0 ] 2> /dev/null || throwError 2 "Paramètre 'taille' incorrect"


# Lancement de la procédure
###############################################################################

fdupes_log="$(date +%y%m%d-%H%M)-fdupes.log"
recherche_doublon $*

# Si aucune ligne du résultat du fdupes ne commence par n chiffres
# Alors on arrête tout de suite
grep -Eq "^[0-9]{$taille}.* byte.* each:$" "$fdupes_log" || throwError 3 "Aucun doublon à lier trouvé"

link_doublons_sh="$(date +%y%m%d-%H%M)-link_doublons.sh"
construire_script

[ -z "$lancerScriptLiaison" ] && read -p "Lancer la liaison des doublons ? (y/Y/o/O/n/N) " lancerScriptLiaison
$VERBOSE || exec 1> /dev/null
echo $lancerScriptLiaison | grep -qE "y|Y|o|O" && ./$link_doublons_sh

Dernière modification par BorX (Le 29/06/2009, à 22:43)

Hors ligne

#2 Le 29/06/2009, à 22:44

BorX

Re : Script Shell qui transforme les fichiers doublons en liens durs

Script modifié : Ajout d'un petit contrôle préalable pour s'assurer de la présence de fdupes sur le système. smile

Dernière modification par BorX (Le 29/06/2009, à 22:45)

Hors ligne

#3 Le 29/06/2009, à 22:53

BorX

Re : Script Shell qui transforme les fichiers doublons en liens durs

Je pense que la section n'était pas la bonne.
J'ai finalement déplacé le sujet dans le forum des développements :
http://forum.ubuntu-fr.org/viewtopic.php?id=328747

Hors ligne

#4 Le 02/07/2009, à 12:36

Vysserk3

Re : Script Shell qui transforme les fichiers doublons en liens durs

Salut,
Le logiciel fslint (sorte de nettoyeur) permet également de faire (entre autres) une recherche de doublons et de les fusionner en hard links wink

Hors ligne

#5 Le 02/07/2009, à 14:07

BorX

Re : Script Shell qui transforme les fichiers doublons en liens durs

Merci wink
C'est à partir d'un forum parlant du traitement des résultats de fdupes que j'ai eu l'idée de ce script.
Une fois développé, j'ai cherché des forums de mecs qui voulaient faire la même chose avec fdupes, et c'est là que j'ai entendu parler de fslint. lol

Cette option est extrêmement pratique et fait cruellement défaut avec fdupes.
Je n'ai pas encore essayé fslint, mais il semble assez génial, comme utilitaire. Donc, tant pis... big_smile
A priori, ce script garde un avantage : le fait de décomposer ce qu'il fait et de bien tout tracer.

En tout cas, merci, c'est gentil d'avoir posté cette info, et pour moi et pour les autres... tongue

Hors ligne