Sommaire
Ce script fonctionne déjà ici en production.
Je cherche à l'optimiser car je l'utilise depuis peu sur un plus gros dossier.
Contexte :
Nous souhaitons effectuer des sauvegardes externes de sorte à prévenir l'incendie ou le cambriolage.
Nous souhaitons que cette copie externe soit chiffrée.
Actuellement, elle se trouve sur un disque externe mais sera bientôt synchronisée à partir d'une machine extérieur, via internet (rsync).
eCryptfs est utilisé dans un premier temps pour obtenir une version chiffrée d'une sauvegarde locale. Mais eCryptfs limite à 110 caractères les noms de fichiers et dossiers.
J'ai donc écrit un script qui parcours l'ensemble du dossier de sorte à tronquer si nécessaire le nom des fichiers et dossier trop long.
Le Script :
Ça marche mais c'est très lent :(
Auriez-vous des idée pour optimiser ce script ? :)
spm_namelength_config.sh
# Define here the maximum end of file name
# to be consider as extension.
# The truncated file name version will keep extension.
#
# Should be greater or equal to 3
#
# Example: 6
#
EXTENTION_MAX_SIZE=6
# Define the hash size for truncated file name.
# Greater hash better avoid collisions but keep
# less original name chars.
#
# Example: 10
#
HASH_SIZE=10
spm_namelength.sh
#!/bin/bash
## Up is a bash function to simplify vertical file system navigation.
##
## Copyright (C) 2013 Serge Smeesters
##
## This program is free software: you can redistribute it
## and/or modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation, either version 3
## of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see http://www.gnu.org/licenses/.
mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
[ -d $mydir ] || exit 4
configfile="$mydir/spm_namelength_config.sh"
if [ -f "$configfile" ]
then
. "$configfile"
else
echo "No config file find :("
exit 4
fi
trunc_item ()
{
local filefullpathname="$1"
local shortsize="$2"
local filefullname=$(basename "$filefullpathname")
if [ ${#filefullname} -gt $sizemax ] ; then
local filepath=$(dirname "$filefullpathname")
local filename=${filefullname%.*}
local filextension=${filefullname##*.}
local hashvalue="$(echo "$filename" | md5sum | cut -c1-$HASH_SIZE)"
echo "---"
echo "$filefullname"
local filextensionsize=${#filextension}
if [ $filextensionsize -gt $EXTENTION_MAX_SIZE ] ; then
local fileshortfullname="$(echo "$filefullname" | cut -c1-$shortsize)$hashvalue"
else
local newsize
(( newsize = shortsize - ( filextensionsize + 1 ) ))
local fileshortname="$(echo "$filename" | cut -c1-$newsize)$hashvalue"
local fileshortfullname="$fileshortname.$filextension"
fi
echo "→ $fileshortfullname"
local fileshortfullpathname="$filepath/$fileshortfullname"
# echo "$fileshortfullpathname"
if [ -e "$fileshortfullpathname" ] ; then
echo "Waw... the shorten file seam to yet exists ! :("
exit 4
fi
pushd "$filepath" >/dev/null
echo "mv \"$fileshortfullname\" \"$filefullname\"" >> .namelengthrestore
mv "$filefullname" "$fileshortfullname"
popd >/dev/null
fi
}
trunc_directory ()
{
local root="$(readlink -f "$1")"
local shortsize="$2"
# echo "(trunc_directory \"$root\""
local directoryfullpathname
find "$root" -mindepth 1 -maxdepth 1 -type d | \
while read directoryfullpathname ; do
trunc_directory "$directoryfullpathname" "$shortsize"
trunc_item "$directoryfullpathname" "$shortsize"
done
local filefullpathname
find "$root" -maxdepth 1 -type f | \
while read filefullpathname ; do
trunc_item "$filefullpathname" "$shortsize"
done
}
restore_directory ()
{
local root="$(readlink -f "$1")"
# echo "(restore_directory \"$root\""
local directoryfullpathname
find "$root" -mindepth 1 -maxdepth 1 -type d | \
while read directoryfullpathname ; do
restore_directory "$directoryfullpathname"
done
if [ -f "$root/.namelengthrestore" ] ; then
pushd "$root" >/dev/null
cat .namelengthrestore
. .namelengthrestore
rm .namelengthrestore
popd >/dev/null
fi
}
main ()
{
if [ $# -lt 2 ] ; then
echo "Less than 2 arguments :("
exit 1
fi
# echo "\$2 : \"$2\""
local root="$(readlink -f "$2")"
# echo "root : \"$root\""
if [ ! -d "$root" ] ; then
echo "\"$root\" don't appear to be a directory :("
exit 1
fi
case "$1" in
trunc)
if [ $# -lt 3 ] ; then
echo "Trunc need 2 arguments..."
exit 2
fi
local sizemax="$3"
if [ ! "$sizemax" ] ; then exit 1 ; fi
local minsizemax
(( minsizemax = 5 * HASH_SIZE + EXTENTION_MAX_SIZE ))
# echo "A reasonable sizemax should be $minsizemax"
if [ "$sizemax" -lt "$minsizemax" ] ; then
echo "sizemax, $sizemax less then minsizemax, $minsizemax :("
exit 1
fi
local shortsize
(( shortsize = sizemax - HASH_SIZE ))
trunc_directory "$root" "$shortsize"
;;
restore)
restore_directory "$root"
;;
*)
echo "Usage: $0 {trunc <DIR> <MAXLENGTH> |restore <DIR>} " >&2
exit 1
;;
esac
}
main "$@"
# Trop de fork
Posté par barmic . Évalué à 4.
J'ai pas regardé dans le détail ce que fait ton algo, mais à vu de nez tu lance un paquet de fois
find
etmd5sum
. C'est dommage. Je pense qu'au lieu de rendretrunc_directory
récursive tu devrait utiliserfind
une bonne fois pour toute et piper son résultat.Tu ne calcul pas le md5 sur le fichier mais sur son nom, ce qui n'est pas très pratique avec la commande md5sum, mais tu devrait pouvoir le faire en perl1 :
Qui va prendre les noms de fichiers en entrée et sortir le hash et le nom de fichier (pas testé). Tu peut ajouter des rafinements coté perl pour ne prendre que le nom du fichier (sans le chemin ni l'extension) et tronquer le hash comme tu le souhaite.
Ainsi finalement tu pourra faire un script de la forme :
Et ça devrait, AMHA, aller beaucoup mieux coté perf (find n'est lancé qu'une fois, perl aussi).
je parle de perl parce que c'est classique d'utiliser perl pour ça, mais tu peux le faire avec ce qui te plaît. ↩
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Trop de fork
Posté par Space_e_man (site web personnel) . Évalué à 2.
C'est chaque nom de dossier et de fichier dont la longueur doit être vérifier et écourter si nécessaire. La somme MD5 est alors utiliser pour éviter les éventuelles collisions.
J'aime pas non plus faire deux find dans chaque dossier de manière récursive.
Mais c'est le seul moyen que j'ai trouvé pour ne pas "scier la branche sur laquelle je suis assis".
Comment utiliser find pour trouver les fichiers et dossiers don le nom est plus long que n caractères ?
Si je ne fait qu'un seul find, le traitement du résultat sera complexe car si je renomme le nom d'un dossier, cela invalide tout les chemins passant par-là… Je devrait donc m'assurer de traiter les résultat dans un ordre bien déterminé… Qu'en pensez-vous ?
[^] # Re: Trop de fork
Posté par barmic . Évalué à 5.
Ça tombe bien, l'option
-depth
defind
est là pour ça. Par défaut il faut un parcourt en largeur avec-depth
, il présente les fichiers et dossiers du dossier courant avant le dossier courant.Au contraire si
find
t'assure d'avoir l'ordre qui va bien tu ne t'occupe plus que de vérifier la taille, faire de la substitution et unmv
qui va bien.Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Trop de fork
Posté par Anthony Jaguenaud . Évalué à 3. Dernière modification le 16 septembre 2014 à 15:49.
A vu de nez, j'aurai écrit
te donnera la liste des noms de fichiers répertoire compris. Tu mets ça dans un
for
puis tu calcule la longueur du nom.[^] # Re: Trop de fork
Posté par Flyounet (site web personnel) . Évalué à 2. Dernière modification le 16 septembre 2014 à 16:20.
Bah un
sort -r
te fera trier traiter les fichiers en premier puis les répertoiresEt encore le
test
sur répertoire est pas vraiment nécessaire, tu travailles sur le nom et pis c'est tout. Ça te permet de remplacer tontrunc_dir
ettrunc_item
.[^] # Re: Trop de fork
Posté par barmic . Évalué à 5.
L'option
--depth
defind
est largement plus efficacesort
demande à ce quefind
finisse totalement son traitement on perd tout l'intérêt du pipe.Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Trop de fork
Posté par Anthony Jaguenaud . Évalué à 3.
J'ai dû mal comprendre le problème initial, car pour moi on parlait de la longueur du nom du répertoire ou du fichier. Pas de la profondeur de la récursivité (
--depth
).[^] # Re: Trop de fork
Posté par Flyounet (site web personnel) . Évalué à 2.
Dans ce que dit Michel, le
-depth
sert à trier comme le ferait le| sort -r
.[^] # Re: Trop de fork
Posté par Michaël (site web personnel) . Évalué à 4.
Tu confonds
-depth
avec-maxdepth
et-mindepth
. L'option-depth
demande àfind
d'explorer l'arborescence de fichiers en profondeur tandisque les deux autres options contrôlent le niveau de récursion.# Nouvelle version...
Posté par Space_e_man (site web personnel) . Évalué à 3.
… beaucoup plus rapide !
Merci à tous :)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.