| AccueilCalendrierVenir aux réunionsContactsMembresDocumentationsLiens Forbach (57) Metz (57) Ventron (88) BacASable |
MirabellugWikiCshIntroductionLe but du jeu est ici est de réaliser un petit script csh pour Debian. Ce script va automatiser la recherche de paquets dont aucun autre ne dépend. Outre des programmes comme grep, sed, cat et Cie, il utilise dpkg et dpkg-query afin de récupérer les informations nécessaires. Côté performances, le temps de traitement est relativement long, principalement à cause des appels répétés aux outils Debian. En revanche, la réalisation d'un tel script est nettement plus aisée que la création d'un programme équivalent en C ou autre, ce qui justifie l'utilisation de la programmation Shell. A noter, pour ceux qui souhaitent éviter le copier-coller, qu'un fichier exécutable est disponible ici. Une fois récupéré, pensez à taper : $ chmod u+x deb-dep.sh Présentation sommaire du scriptComme il le dit lui-même (deb-dep.sh --usage), le petit script accepte quelques arguments lors de son appel :
Le script travaille sur quatre fichiers temporaires :
Ces fichiers sont bien sûr effacés après usage. Quelques mots sur le codeLes commandes décrites ici ne seront pas détaillées (RTFM). Concernant le code Csh :
foreach element ($liste)
...
end
Cette boucle décompose le contenu de la variable $liste en mots. A chaque itération, un mot est mis dans la variable $element. La boucle se termine quand tous les mots ont été traités. Par ailleurs, '$liste' peut être remplacée par une commande Shell. Par exemple, pour parcourir le fichier tmp : foreach element (`cat tmp`). cat tmp_lst2 | grep -v $target > tmp_lst2b mv tmp_lst2b tmp_lst2 Description de la procédure : on ouvre le contenu du fichier tmp_lst2 (cat) et on envoie son contenu (|) vers grep, qui va laisser passer toutes les lignes ne contenant pas $target. Les lignes ayant passé les mailles du filet servent à créer (>) le fichier temporaire tmp_list2b. On renomme (mv) ensuite ce dernier en tmp_lst2. Ici, on est obligé de passer par un second fichier. En effet, mettre '> tmp_lst2' reviendrait à écraser le fichier que l'on est en train de lire, ce qui ne passerait pas sans perte de données. set nb = 1 ... @ nb++ Le '@' permet d'indiquer à l'interpréteur que le contenu de la variable est à manipuler en tant que forme numérique, et non chaîne de caractères. Ici, nb est un compteur indiquant le numéro du paquet traité.
set dep_list = `dpkg-query -p $pkg >& /dev/null`
if ($status == 0) then
set dep_list = `dpkg-query -p $pkg | grep ...
...
Il arrive parfois qu'un paquet installé n'est aucune description (!?!) ; le cas s'est produit avec alsaplayer-als. Dans ce cas de figure, >& /dev/null évacue tous les messages (erreurs et autres). C'est là qu'intervient la variable $status, qui contient le code de sortie du dernier programme exécuté. Ainsi, on ne continue ici que si l'appel à dpkg-query s'est effectué correctement ($status = = 0). Afin de diminuer le temps de traitement, on aurait pu eviter le second appel à dpkg-query avec : dpkg-query -p $pkg > fichier >& /dev/null (cf. man csh) Dans la pratique, l'interpréteur indique que la sortie de la commande est ambigüe... -> solution à la trappe ! sort tmp_comp1 > tmp_comp2 Un petit mot sur la méthode de comparaison des numéros de version : même s'ils sont très reglementés, les formats présents sont vraiment très hétéroclites (dpkg -l pour vous en convaincre !). Aussi, le programme sort est quelque fois dépassé. Un bel exemple est la comparaison entre '2.3.2.ds1-11' et '2.3.2.ds1-4' : '1' étant inférieur à '4', '2.3.2.ds1-4' est une version plus récente que '2.3.2.ds1-11' ! C'est pourquoi l'utilisation des numéros de version n'est ici que pour l'exemple, et que de telles comparaisons sont déconseillées du fait de leur manque de fiabilité. Code source
#!/bin/csh
########################################################
## +++ LECTURE DES EVENTUELS PARAMETRES FOURNIS +++ ##
########################################################
set fichier = '~/.debpkg'
# Par défaut
set bavard = 'oui'
set usage = 'non'
set vverif = 'non'
set filtre = 'oui'
# Lecture de la ligne de commande
foreach arg ($argv)
switch ($arg)
case '-s':
set bavard = 'non'
breaksw
case '--usage':
case '--help':
set usage = 'oui'
breaksw
case '-f':
set vverif = 'oui'
breaksw
case '-r':
set filtre = 'non'
breaksw
endsw
end
# Affichage éventuel de la marche à suivre
if ($usage == 'oui') then
echo "$0 -- Détermination des paquets non nécessaires"
echo "Usage : $0 [-s] [-f] [--usage] [--help]"
echo ' -s : mode Silencieux'
echo ' -f : Force la vérification des numéros de version (déconseillé)'
echo " -r : ne filtre pas le résultat final avec le fichier $fichier"
echo ' --usage : affiche ce message'
echo ' --help : affiche ce message'
exit 0
endif
##############################################
## +++ CONSTITUTION DE LA LISTE BRUTE +++ ##
##############################################
# Récupération de la liste totale
dpkg -l | grep '^[A-Za-z]\{2\} ' > tmp_lst
# Mise sous forme 'nom_paquet@version'
cat tmp_lst | grep '^[A-Za-z]\{2\} ' | sed 's/.\{4\}\([^ ]*\) *\([^ ]*\).*/\1@\2/' > tmp_lst2
cp tmp_lst2 tmp_lst
if ($bavard == 'oui') then
echo "Traitement de `wc -l tmp_lst | sed 's/\([0-9]*\).*/\1/' ` paquets..."
set nb = 1
endif
# Pour chaque paquet installé
foreach line (`cat tmp_lst`)
set pkg = `echo $line | sed 's/\([^@]*\).*/\1/'`
if ($bavard == 'oui') then
echo " [$nb] $pkg... (`wc -l tmp_lst2 | sed 's/\([^ ]*\).*/\1/'`)"
@ nb++
endif
# On récupère la liste...
set dep_list = `dpkg-query -p $pkg >& /dev/null`
if ($status == 0) then
# ...sous forme 'pkg[@(>=|>>|...)@version] pkg[@(>=|>>|...)@version] ...'
set dep_list = `dpkg-query -p $pkg | grep Depends | sed 's/Depends: \(.*\)$/\1/' | sed 's/\([^ ]*\) (\([^ ]*\) \([^ ]*\)),\? \?/\1@\2@\3 /g' | sed 's/,//g'`
# Parcours de la liste des paquets requis
foreach dep ($dep_list)
set name = `echo $dep | sed 's/\([^@]*\).*/\1/'`
set comp = `echo $dep | grep @ | sed 's/[^@]*@\([^@]*\).*/\1/'`
set version = `echo $dep | grep @ | sed 's/[^@]*@[^@]*@\(.*\)/\1/'`
# Parcours des paquets éjectables
foreach target (`grep $name@ tmp_lst2`)
if ($vverif == 'non') then
set suppr = 'oui'
else
set tname = `echo $target | sed 's/\([^@]*\).*/\1/'`
set tversion = `echo $target | grep @ | sed 's/[^@]*@\([^@]*\)/\1/'`
set suppr = 'non'
echo $version > tmp_comp1
echo $tversion >> tmp_comp1
# Partie délicate en raison des nombreux formats de version
# par ex, ne marche pas avec '2.3.2.ds1-11' et '2.3.2.ds1-4'
sort tmp_comp1 > tmp_comp2
set second = `tail -1 tmp_comp2`
if ($second == $version) then
set premier = $tversion
else
set premier = $version
endif
switch ($comp)
case '>=':
if ($premier == $version || $premier == $second) then
set suppr = 'oui'²
endif
breaksw
case '>>':
if ($premier == $version) then
set suppr = 'oui'
endif
breaksw
case '<=':
if ($premier == $tversion || $premier == $second) then
set suppr = 'oui'
endif
breaksw
case '\<\<':
if ($premier == $tversion) then
set suppr = 'oui'
endif
breaksw
default:
set suppr = 'oui'
breaksw
endsw
endif
if ($suppr == 'oui') then
cat tmp_lst2 | grep -v $target > tmp_lst2b
mv tmp_lst2b tmp_lst2
endif
end
end
endif
end
################################################
## +++ SUPPRESSION DES FICHIERS FAVORIS +++ ##
################################################
# Supression des fichiers que l'on souhaite garder
if ($filtre == 'oui') then
test -r $fichier
# Si le fichier existe et est lisible
if ($status == '0') then
foreach element (`cat $fichier`)
cat tmp_lst2 | grep -v $element > tmp_lst2b
mv tmp_lst2b tmp_lst2
end
endif
endif
cat tmp_lst2 | sed 's/\([^@]*\).*/\1/'
rm -f tmp_lst
rm -f tmp_lst2
rm -f tmp_comp1
rm -f tmp_comp2
Il y a un commentaire sur cette page.
[Afficher commentaires/formulaire]
|