Debian-facile

Bienvenue sur Debian-Facile, site d'aide pour les nouveaux utilisateurs de Debian.

Vous n'êtes pas identifié(e).

#1 22-04-2009 02:57:16

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

apt-diag et les paquets seront bien gardés

dernière version: 0.2b (toujours utiliser la dernière version).

v.0.2b plus bas. La version 0.1 ainsi que la version 0.2 dans une moindre mesure sont affectées d'un bug dans la fonction f_updatecache, ne pas les utiliser et supprimer le cache s'il y a eu des mises à jour ou en cas de doute.


Bonjour à tous !

j'ai eu un peu de temps ces dernières semaines (la crise toussa) et j'en ai profité pour faire un script qui je pense peut être utile à pas mal de monde. Peut-être découvrirez-vous des choses sur votre système...

J'ai fait ce script d'abord pour me perfectionner en bash (ce qui explique certains choix et certains "amusements"), donc si vous avez des remarques, des conseils, des améliorations,... n'hésitez pas. Je dois dire que j'ai sauté sur l'occasion d'avoir une idée qui me paraissait intéressante: je crois que le plus dur en programmation c'est d'avoir une idée :)

Pour ce qui est des fonctionnalités d'apt-diag c'est pareil: n'hésitez pas à proposer des améliorations/ajouts ou à les coder et à nous en faire profiter. Essayez juste si possible de rester dans l'esprit du script.

Il y a une description générale en commentaire au début, donc j'en ajoute pas plus.

Vous pourrez trouver un système de test ici, à placer dans ~/.apt-diag. Il rassemble les cas traités par apt-diag pour permettre d'en tester les fonctionnalités.

Voilà. J'ai deux souhaits: que apt-diag vous soit utile et que peut-être il inspire un vrai programmeur Debian pour qu'une application de ce type soit intégrée au système.


#!/bin/bash

############                                                           #########
# apt-diag #                                                           # v.0.1 #
################################################################################
# author: (C)2009 nofun_AT_laposte_DOT_net ## bug report, suggestion, wishlist #
####################################################### are welcome ############
# GNU General Public License v.3 or later http://www.gnu.org/copyleft/gpl.html #
################################################################################

# apt-diag: pour que claires les sources demeurent

# apt-diag cherche a donner une vue d'ensemble des paquets installes sur un
# systeme utilisant apt (Advanced Packaging Tool du projet Debian).
# Il aide en particulier a determiner de quelle source peut provenir un paquet,
# indique quand c'est le cas la presence d'un meme paquet dans de multiples
# sources et dresse la liste des paquets n'appartenant plus a aucune source
# (ensemble des paquets obsoletes et des paquets de source inconnue).
# C'est un bon complement a 'apt-cache policy nom_du_paquet'.

# De plus, apt-diag maintient un cache personnel des paquets par source, ce qui
# lui permet d'etablir la liste des paquets obsoletes en provenance de chaque
# source, information sinon indisponible. Les sources supprimees sont egalement
# archivees. Le degre d'information que fournit apt-diag est donc dependant de
# la date d'initialisation du cache.

# apt-diag n'agit pas sur le systeme de gestion des paquets, il est donc su^r
# pour le systeme hote. Le seul appel au systeme de gestion des paquets est du
# type 'dpkg -l' ou 'dpkg --get-selections'. De ce fait, apt-diag peut analyser
# un systeme autre que le systeme hote si on lui fournit les repertoires
# /var/lib/apt/lists/ et /var/lib/dpkg/ d'un syteme alternatif et fonctionne
# parfaitement en simple utilisateur.

# Limitations:
# tout diagnostic est faillible et sujet a des erreurs d'interpretation. Il
# appartient a l'administrateur d'evaluer les informations fournies par apt-diag
# en particulier en confrontant les resultats obtenus avec ceux que pourront lui
# procurer les outils systeme a sa disposition. La licence GNU GPL sous laquelle
# apt-diag est delivre n'offre aucune garantie de bon fonctionnement.
# apt-diag n'a pas (encore) ete teste en presence de downgrade ou d'apt-pinning
# et plus generalement demande a etre teste davantage.
# apt-diag n'est pas integre au systeme de gestion des paquets, de ce fait la
# mise a jour du cache n'est pas automatique lors de la mise a jour du systeme.
# apt-diag evalue les paquets par leur nom, l'evaluation par numero de version
# est embryonnaire et demanderait d'autres techniques de programmation.
# Si un paquet a ete installe depuis une source par la suite supprimee et que ce
# paquet apparait toujours dans une autre source avec une version inferieure,
# rien de particulier n'est signale au sujet de ce paquet par apt-diag.

# Merci de distribuer apt-diag avec le texte ci-dessus.
# Bonne utilisation.

################################################################################
PROGNAME=$(basename $0)

f_conv()
{
    #TestCharSet: aéèêîïà¿»×x
    grep -m 1 "TestCharSet:" $0 > /tmp/testcharset
    PRGCHARSET=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'|tr [a-z] [A-Z]`
    SYSCHARSET=$(locale charmap)
    ! echo $SYSCHARSET|grep -q $PRGCHARSET && echo -e "\n [>] Conversion de $PROGNAME de $PRGCHARSET vers $SYSCHARSET...\c"\
    && { iconv -f "$PRGCHARSET" -t "$SYSCHARSET"//TRANSLIT $0 -o /tmp/$PROGNAME && chmod +x /tmp/$PROGNAME\
    && grep -m 1 "TestCharSet:" /tmp/$PROGNAME > /tmp/testcharset && PRGCHARSETR=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'`\
    && { [ "$PRGCHARSET" = "$(echo $PRGCHARSETR|tr [a-z] [A-Z])" ] && echo " ok" || echo; } && rm -f /tmp/testcharset\
    && echo -e " [*] la version $PRGCHARSETR de $PROGNAME est disponible dans /tmp/$PROGNAME\n" && exit\
    || { echo -e "\a\n [!] un probleme est survenu pendant la conversion, sortie\n"; exit 1; }; }
}
[ -d ~/.$PROGNAME ] || { f_conv; [ -d /var/lib/apt/lists/ ] && [[ $(dpkg -l 2>/dev/null) ]]\
|| { echo -e "\a\n [!] $PROGNAME n'est pas compatible avec le système hôte, sortie\n"; exit 1; }; }

which bc &>/dev/null|| { echo -e "\a\n [>] $PROGNAME\n [!] Ce script nécessite bc pour fonctionner, veuillez l'installer:\n"
aptitude show bc; echo -e "\n [*] aptitude -(s)v install bc\n"; exit 1; }

[ "$1" = "-c" ] && ECHO=echo || CLEAR=clear ; hash grep mawk
grep -q "Ratio $(uname -n):" ~/.$PROGNAME/ratio 2&>/dev/null && RATIO=`grep "Ratio $(uname -n):" ~/.$PROGNAME/ratio|cut -d " " -f3`
################################################################################

f_clearline()
{
    [[ $1 = [br] ]] && [ -n "$3" ] && echo $2$3|grep -qx [0-9]* || return 1
    while true
    do
  local COUNTER; let COUNTER++ ; echo -ne "\\$1"
  [ $COUNTER = $2 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; echo -ne " "
  [ $COUNTER = $3 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; [ $1 = r ] && COUNTER=$3
  echo -ne "\\$1" ; [ $COUNTER = $3 ] && return
    done
}

f_exit() { read -s -n 1 -p " [¿] Quitter $PROGNAME ? <O/n>: " EXIT; [ "$EXIT" = n ] && f_clearline r 1 45 && return; echo; echo; exit; }

f_init()
{
    for (( s=1; s <= TSOURCES; s++ )); do unset -v RESULTF$s OBSOLETES$s; done
    unset -v DEL INEWS ISUPR NOPURGEP NOSOURCEDP OBSOLETES OBSOLETEST OBSOLETESTC OBSOLETESTR
    unset -v RESULTF RESULTFT SINGLE SOURCEDP SOURCESG SOURCESGC SOURCESN SOURCESNG TSOURCES TWIN TWINP

    CACHEDIR=~/.$PROGNAME/$MACHINE/cache ; RECFILE=~/$PROGNAME\_$MACHINE\-$(date +%Y%m%d-%H%M%S).txt
    [ -d $CACHEDIR ] || {  mkdir -p $CACHEDIR/.old/sources/.deleted/ $CACHEDIR/sources/
    echo "$MACHINE $(date "+%F %T") initialisation du cache" >> ~/.$PROGNAME/$MACHINE/history.txt; }
    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ]\
    && mv -f ~/.$PROGNAME/_alternate/lists/ ~/.$PROGNAME/_alternate/dpkg/ ~/.$PROGNAME/$MACHINE/
    [ "$MACHINE" = "$(uname -n)" ] && SOURCESDIR=/var/lib/apt/lists/ INSTALLDIR=/var/lib/dpkg/\
    || SOURCESDIR=~/.$PROGNAME/$MACHINE/lists/ INSTALLDIR=~/.$PROGNAME/$MACHINE/dpkg/

    ## extraction de la liste des paquets installes sur le systeme
    INSTALLED=$(dpkg --admindir=$INSTALLDIR --get-selections |grep -w "install$" |mawk '{print $1}' |sort -d)
    NINSTALLED=$(echo $INSTALLED | wc -w)
    ## extraction et nettoyage des sources
    SOURCES=$(ls $SOURCESDIR |grep -vx lock |grep -vx partial)
    for a in _source_Sources i18n_Translation .ed$
    do
  SOURCES=$(printf '%b\n' $SOURCES | grep -v $a)
    done
    for s in $SOURCES
    do
  grep -qm 1 "^Package: " $SOURCESDIR$s || continue
  SOURCESC="$SOURCESC $s" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v SOURCESC
    echo " [»] Paquets installés: $INSTALLDIR Paquets disponibles: $SOURCESDIR"
    echo " [»] $NINSTALLED paquets installés sur $MACHINE"
}

f_progress()
{
    let PROGRESS++
    [ $PROGRESS = $ALPHAPROGRESS ] && echo -ne "\b-" && return
    [ $PROGRESS = $ALPHAPROGRESS2 ] && echo -ne "\b\\" && return
    [ $PROGRESS = $ALPHAPROGRESS3 ] && echo -ne "\b|" && return
    [ $PROGRESS = $ALPHAPROGRESS4 ] && echo -ne "\b/" && PROGRESS=0
}

f_benchmachine()
{
    local ALPHAPROGRESS ALPHAPROGRESS2 ALPHAPROGRESS3 ALPHAPROGRESS4 BURN COUNTER PROGRESS SAMPLE SAMPLEb TEMPS TEMPS1 TEMPS2
    ALPHAPROGRESS=60 SAMPLE="sourceinstalled" # ! la taille du mot est importante ! ne pas modifier ! SAMPLE="sourceinstalled"
    ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
    f_burn()
    {
  CLOCKD=$(date +%s%N)
  while true
  do
      let COUNTER++; f_progress
      while true
      do
          let COUNTERb++; f_progress
          SAMPLEb="$SAMPLEb $(echo "$SAMPLE ")"
          [ $COUNTERb = 100 ] && break
      done
      unset -v COUNTERb
      echo $SAMPLEb|grep $SAMPLE|wc -w &>/dev/null
      [ $COUNTER = 10 ] && break
  done
  CLOCKF=$(date +%s%N)
  let BURN++
    }
    [ "$BURN" = "" ] && echo -n " [>] Benchmarking machine...  " && f_burn
    [ "$BURN" = "1" ] && unset -v COUNTER SAMPLEb && f_burn
    [ "$BURN" = "2" ] && TEMPS1=$(($CLOCKF-$CLOCKD)) && unset -v COUNTER SAMPLEb && f_burn
    TEMPS2=$(($CLOCKF-$CLOCKD)) TEMPS=$(($TEMPS1+$TEMPS2))
    RATIO=$(echo "scale=20;$TEMPS/2/$COUNTER/240000000"|bc|mawk '{printf "%0.1f\n",$1}')
    ## ($RATIO=1 est obtenu sur mon portable Core2Duo T7250 2GHz 2Go RAM, $RATIO>1 sur une machine plus lente)
    ## le resultat peut etre faux sur un portable non branche ou si une autre application prend de la ressource
    echo "Ratio $(uname -n): $RATIO" > ~/.$PROGNAME/ratio
    f_clearline r 1 35
}

f_benchmark()
{
    [ -z "$RATIO" ] && f_benchmachine; echo -n " [>] Benchmarking...  "; local RESULTF PROGRESS COUNTER
    ## ALPHACOUNTER: determine un nombre de boucles proportionnellement inverse au nombre de paquets dans la source pondere par le ratio machine
    ## destine a adapter le temps de bench en prenant en compte $NPA et la vitesse de la machine
    PREALPHACOUNT=`echo "scale=20;1/$NPA*150000*1/(1/$NPA*(300+$NPA/2))*1.8"|bc`
    ALPHACOUNTER=`echo "scale=20;$PREALPHACOUNT/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
    [ `echo "scale=0; $ALPHACOUNTER<2"|bc` -eq 1 ] && ALPHACOUNTER=2
    CLOCKD=$(date +%s%N)
    for i in $INSTALLED
    do
  let COUNTER++; f_progress
  RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $i)"
  [ $COUNTER -eq $ALPHACOUNTER ] && break
    done
    CLOCKF=$(date +%s%N)
    TEMPS=$(($CLOCKF-$CLOCKD)) BENCHMASS=$(($NPA*$COUNTER)) BENCH=$(echo "scale=10;$TEMPS/$BENCHMASS"|bc)
    f_clearline r 1 30
}

f_estimate()
{
    ESTIMATE=$(echo "scale=10;$BENCH*$COMPUTEMASS"|bc)
    ESTIMATEHS=$(echo "scale=0;$ESTIMATE/1000000000"|bc)
    ESTIMATEHSBC=$(echo "scale=3;$ESTIMATE/1000000000"|bc)
    mn=0 ss=$ESTIMATEHS ms=$(echo "$ESTIMATEHSBC-$ss"|bc|cut -d '.' -f2)
    [ $ESTIMATEHS -gt 59 ] && mn=$(($ESTIMATEHS/60)) && ss=$(($ss-$mn*60))
    [ $ss -lt 10 ] && ss="0$ss"
    ESTIMATE=$(echo ""$mn"m"$ss"s"$ms"ms")
}

f_mkcache()
{
    trap 'echo -e "\a\n$PROGNAME > WARNING! The disk cache might be left in an inconsistent state!"; f_exit' 2 3 9 15
    ## determine s'il y a des nouvelles sources a traiter:
    for s in $SOURCES; do [ -f $CACHEDIR/sources/$s ] && continue; SOURCESNEWS="$SOURCESNEWS $s"; let TSOURCESM++; done
    ## determine si des sources ont ete desactivees, dans ce cas les archive:
    ## NB: les depots designes par les noms de code des versions (ex. lenny) seront archives au changement de version,
    ## ceux utilisant la terminologie stable, testing, unstable,... seront traites par f_updatecache
    for s in $(ls $CACHEDIR/sources/)
    do
  printf '%b\n' $SOURCES|grep -qxm 1 $s &>/dev/null || { mv -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/.deleted/$s; DEL="$DEL $s"; }
    done
    [ -n "$DEL" ] && echo && for d in $DEL; do echo " [>] Archivage de la source supprimée $d";\
    echo "$MACHINE $(date "+%F %T") source supprimée $d archivée" >> ~/.$PROGNAME/$MACHINE/history.txt; done
    [ -z "$TSOURCESM" -a -n "$DEL" ] && { unset -v DEL; echo; echo >> ~/.$PROGNAME/$MACHINE/history.txt
    read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR; return; }; [ -z "$TSOURCESM" ] && return
    echo
    echo " [>] Création du cache initial de paquets installés pour les nouvelles sources:"; echo
    time\
    for a in $SOURCESNEWS
    do
  ## supprime la source du repertoire .deleted si elle a ete reactivee
  [ -f $CACHEDIR/.old/sources/.deleted/$a ] && rm -f $CACHEDIR/.old/sources/.deleted/$a
  ## ecrit dans $CACHEDIR/sources/$a les noms des paquets installes qui ont une occurrence dans $SOURCESDIR$a
  local TIMEFORMAT=" »»»  réelle: %lR" PROGRESS CSOURCES; let CSOURCES++
  echo " [»] Traitement de la source ($CSOURCES/$TSOURCESM) $a"
  PRERESULT=$(grep "^Package: " $SOURCESDIR$a | mawk '{print $2}') NPA=$(echo $PRERESULT | wc -w) COMPUTEMASS=$(($NPA*$NINSTALLED))
  echo " [»] $NPA paquets dans la source, $NINSTALLED paquets installés sur $MACHINE"
  [ -z "$RATIO" ] && f_benchmachine
  ### ALPHAPROGRESS: alteration proportionnelle de l'indicateur de progresssion. Utilise le nombre inverse de $NPA, pondere par $RATIO
  PREALPHAPROG=`echo "scale=20;1/$NPA*(200+$NPA)*10"|bc`
  [ `echo "scale=20; $PREALPHAPROG<=11"|bc` -eq 1 ]\
  && ALPHAPROGRESS=`echo "scale=20;(($PREALPHAPROG-10)*10+$PREALPHAPROG-10)/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`\
  || ALPHAPROGRESS=`echo "scale=20;$PREALPHAPROG/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS<1"|bc` -eq 1 ] && ALPHAPROGRESS=1
  [ `echo "scale=0; $ALPHAPROGRESS>20"|bc` -eq 1 ] &&\
  ALPHAPROGRESS=`echo "scale=20;20+(-1/$ALPHAPROGRESS+$ALPHAPROGRESS)/$NPA/1*$NPA/10"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS>30"|bc` -eq 1 ] && ALPHAPROGRESS=30
  ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
  f_benchmark
  f_estimate
  [ "$ESTIMATEHS" -lt 120 ] && echo -n " [»] durée estimée de traitement: $ESTIMATE  "\
  || echo -n " [»] durée estimée de traitement: $ESTIMATE (début $(date +%T))  "
  time\
  for WORKAROUND in 1
  do
      for b in $INSTALLED
      do
    f_progress
    RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $b)"
      done
      f_clearline b 1 1
  done
  printf '%b\n' $RESULTF|sort -d > $CACHEDIR/sources/$a
  echo "$MACHINE $(date "+%F %T") nouvelle source $a ajoutée" >>~/.$PROGNAME/$MACHINE/history.txt
  RESULTFC=$(echo $RESULTF | wc -w)
  [ $RESULTFC -ne 0 ] && echo " [*] $RESULTFC occurrences" || echo " [×] pas d'occurrence"
  echo ; unset -v PROGRESS RESULTF
  [ $TSOURCESM = $CSOURCES ] && local TIMEFORMAT=" [»] durée totale de traitement: %lR" && unset -v DEL SOURCESNEWS TSOURCESM
    done
    echo >>~/.$PROGNAME/$MACHINE/history.txt; echo; echo; read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR
}

f_updatecache()
{
    mv -f $CACHEDIR/Installed $CACHEDIR/.old/ 2>/dev/null; printf '%b\n' $INSTALLED > $CACHEDIR/Installed
    [ -f $CACHEDIR/.old/Installed ] || return
    ISUPR=$(echo $(diff -y --suppress-common-lines $CACHEDIR/.old/Installed $CACHEDIR/Installed |cut -d'>' -f1 |cut -d'<' -f1))
    INEWS=$(echo $(diff -y --suppress-common-lines $CACHEDIR/.old/Installed $CACHEDIR/Installed |cut -d'>' -f2 |cut -d'<' -f3))
    [ -z "$ISUPR" -a -z "$INEWS" ] && return
    echo -e "\n [>] Mise à jour du cache...\c"; mv -f $CACHEDIR/sources/* $CACHEDIR/.old/sources/ 2>/dev/null
    for s in $(ls $CACHEDIR/.old/sources/)
    do
  ## supprime du cache les occurrences desinstallees
  for r in $ISUPR
  do
      grep -vx "$r" $CACHEDIR/.old/sources/$s > $CACHEDIR/sources/$s && cp -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/$s
  done
  PRERESULT=$(grep "^Package: " $SOURCESDIR$s | mawk '{print $2}')
  cp -uf $CACHEDIR/.old/sources/$s $CACHEDIR/sources/$s
  ## ajoute au cache les nouvelles occurrences installees si elles apparaissent dans la source sauf si elles y sont deja
  for n in $INEWS
  do
      grep -qxm 1 "$n" $CACHEDIR/sources/$s &>/dev/null && continue
      echo "$PRERESULT"|grep -xm 1 "$n" >> $CACHEDIR/sources/$s
  done
  printf '%b\n' $(echo $(sort -d $CACHEDIR/sources/$s)) > $CACHEDIR/sources/$s
    done
    rm -f $CACHEDIR/.old/sources/* 2>/dev/null; f_clearline r 1 30
    ## il est a noter que les paquets obsoletes (plus presents dans les sources) sont conserves dans le cache et analysables comme obsoletes
}

f_selectsources()
{
    unset -v RESUME TSOURCES
    ## formatage des sources pour la presentation, comptage des sources, presentation
    for a in $SOURCES
    do
  [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
  && SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}') $a"\
  || SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1}') $a"
  let TSOURCES++
    done
    [ -n "$ISUPR" -o -n "$INEWS" ] || echo; unset -v ISUPR INEWS
    echo " [>] $TSOURCES sources de paquets actuellement sélectionnées pour analyse:"
    echo ; unset -v TSOURCES
    printf ' [%b]\t» %b\n' $SOURCESP
    echo
    read -p " [¿] Sélectionner ou éliminer (préfixe «-») un motif pour filtrer, valider pour terminer: " MOTIF
    ## si le MOTIF est vide, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    [ "$MOTIF" = "" ] && SOURCESS=$SOURCES
    until [ "$MOTIF" = "" ]
    do
  MOTIFS="$MOTIFS $MOTIF"
  read -p " [¿] continuer la sélection des sources à analyser, valider pour terminer: " MOTIF
    done
    ## s'il n'y a que des eliminations, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    for m in $MOTIFS ; do MOTIFC="$(echo $m | cut -c 1) $MOTIFC" ; done
    MCM=$(printf '%b\n' $MOTIFC | grep -c "-") MC=$( printf '%b\n' $MOTIFC | grep -c "")
    [ "$MCM" = "$MC" ] && SOURCESS=$SOURCES
    ## boucle d'inclusion. La boucle interne permet de ne pas inclure une source deja presente (doublon)
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" != "-" ] && SELECT=$(printf '%b\n' $SOURCES | grep $MOTIF) || continue
  for s in $SELECT
  do
      [[ $(printf '%b\n' "$SOURCESS" | grep -w "$s") ]] && continue
      SOURCESS="$SOURCESS $s"
  done
    done
    ## boucle d'exclusion
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" = "-" ] && MOTIF=$(echo $MOTIF | cut -c 2-) && SOURCESS=$(printf '%b\n' $SOURCESS | grep -v $MOTIF)
    done
    SOURCES=$SOURCESS
    echo
    ## exclusion des fichiers qui ne sont pas des descripteurs de paquets
    echo " [>] Analyse des sources:"
    [ "$SOURCES" != "" ] && NSOURCES=$(printf '%b\n' $SOURCES | grep -c "") || NSOURCES=0
    for a in $SOURCES
    do
  if ! grep -qm 1 "^Package: " $SOURCESDIR$a
  then
      [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
      && b=$(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}')\
      || b=$(ls -sh $SOURCESDIR$a | mawk '{print $1}')
      echo " [×] non pertinente: $a [$b]"
      continue
  fi
  SOURCESC="$SOURCESC $a" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v MOTIFC MOTIFS SOURCESC SOURCESP SOURCESS
    [ "$SOURCES" = "" ] && TSOURCES=0
    [ "$TSOURCES" != "0" ]\
    && SOURCES=$(printf '%b\n' $SOURCES|sort -d) SOURCES=$(echo $SOURCES)\
    && echo " [»] $TSOURCES sources sur $NSOURCES à traiter dans la sélection:" && printf ' [*] [%b]\n' $SOURCES\
    || echo " [»] pas de sources à traiter dans la sélection"
    echo
    while true; do let COUNT++; echo ${FUNCNAME[$COUNT]}|grep -qx main && MAIN=$COUNT && unset -v COUNT && break; done
    RESUME=* ; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    while true
    do
  case "$RESUME" in
      q|Q) f_exit; RESUME=*;;
      h)  less $0; RESUME=*;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break $MAIN; };;
      p)  [ "$TSOURCES" != "0" ] && $CLEAR && f_selectsources || RESUME=r;;
      l|L|"") [ "$TSOURCES" != "0" ] && break || [ "$RESUME" = "" ] && RESUME=r || RESUME=*;;
      r|R) $CLEAR; f_init; f_selectsources;;
      *)  [ "$TSOURCES" != "0" ]\
    && read -s -n 1 -p " [¿] Préciser encore la sélection - Recommencer - Lancer l'analyse <p/r/L>: " RESUME\
    && f_clearline r 1 104
    [ "$TSOURCES" = "0" ] && read -s -n 1 -p " [¿] Recommencer <R>: " RESUME && f_clearline r 1 50;;
  esac
    done
}

f_occm()
{
    while true
    do
  read -s -n 1 -p " [¿] Par la suite traiter aussi les sources sans occurrences ? <o/N>: " SELECT
  f_clearline r 1 75
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break 2; };;
      o|O)  OCCLESS=0 ; unset -v SELECT ; $CLEAR ; break;;
      n|N|"") OCCLESS=1 ; unset -v SELECT ; $CLEAR ; break;;
  esac
    done
}

f_squeezecache()
{
    echo
    for s in $SOURCES
    do
  local CSOURCES CSOURCESM CSOURCESS ; let CSOURCES++ ; let CSOURCESS++
  RESULTF=$(cat $CACHEDIR/sources/$s) RESULTFC=$(echo $RESULTF | wc -w)
  ## eval interprete l'item suivant dans la liste comme une commande s'il y a un espace
  RESULTF=`echo $RESULTF|mawk '{gsub(" ","¿");print $0}'`
  ## attribution d'une variable dynamique au resultat individuel - utilisation de eval
  ## identification par le n° de traitement $CSOURCES, attribution du contenu de RESULTF a la nouvelle variable
  ## la nouvelle variable recoit le nom de la source en alias, permet la concordance n°/nom
  [ $RESULTFC -ne 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [*] $RESULTFC occurrences\t$s"
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [×] pas d'occurrence\t$s" && let CSOURCESM++
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 1 ] && let CSOURCES-- && echo -e " [×] pas d'occurrence\t$s"
  unset -v RESULTF
    done
    echo ; TSOURCES=$CSOURCES ; [ -z $CSOURCESM ] && CSOURCESM=0
    echo " [»] $(($CSOURCES - $CSOURCESM)) sources sur $CSOURCESS présentent des occurrences de paquets installés sur $MACHINE"
    echo ; unset -v CSOURCESM CSOURCESS CSOURCES
    ## concatenation des resultats individuels - utilisation de la substitution de variable {!RESULTF}
    for (( n=1; n <= TSOURCES; n++ ))
    do
  RESULTF=RESULTF$n ## RESULTF se substitue a la variable dynamique dont le contenu est appele par {!RESULTF}
  RESULTFP=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTFP=$(echo $RESULTFP)
  RESULTFT="$RESULTFT $RESULTFP" ## concatenation, doublons compris elimines par sort -u par la suite
  SOURCESN="$SOURCESN $n" ## extrait les numeros des sources disponibles de 1 a n sources
    done
    SOURCESN=$(echo $SOURCESN) SOURCESNP=`echo $SOURCESN|mawk '{gsub(" ","\&|");print $0}'`
    RESULTFTS=$(printf '%b\n' $RESULTFT | sort -d) RESULTFTU=$(echo $(printf '%b\n' $RESULTFT | sort -u))
    RESULTFTC=$(echo $RESULTFT|wc -w) RESULTFTUC=$(echo $RESULTFTU|wc -w) RESULTFTCC=$(($RESULTFTC-$RESULTFTUC))
    UNKNOWNS=$(printf '%b\n' $INSTALLED $RESULTFTU|sort -d|uniq -u) UNKNOWNC=$(echo $UNKNOWNS|wc -w)
    NOPURGE=`dpkg --admindir=$INSTALLDIR -l|grep "^rc "|mawk '{print $2}'` NOPURGEC=$(echo $NOPURGE|wc -w)
    echo
    echo " [*] paquets installés sur $MACHINE: $NINSTALLED"
    echo " [*] occurrences installées sur $MACHINE: $RESULTFTUC"
    echo " [*] paquets installés non analysés: $(($NINSTALLED-$RESULTFTUC))"
    echo " [*] croisements d'occurrences: $RESULTFTCC"
    echo " [*] occurrences totales: $RESULTFTC"
    echo
}

f_postproc()
{
    f_fmt() { fmt -w $(tput cols); }
    f_tee() { [ $RECORD = 1 ] && tee -a $RECFILE || tee; }
    f_less() { [ $LESS = 1 ] && less -m~ || tee; }
    f_pager()
    {
  read -s -n 1 -p " [¿] afficher les occurrences avec Less - directement - ne pas afficher <L/d/n>: " PAGER
  f_clearline r 1 80 ; [ "$PAGER" = "d" -o "$PAGER" = "n" ] || PAGER=L ; PAGERM="\c"
  [ "$PAGER" = L ] && LESS=1 PAGERM="      [affichage dans le pager]" || LESS=0; [ "$PAGER" = n ] && PAGERM="      -------------------------"
    }
    f_adv()
    {
  trap 'break' SIGUSR1
  while true
  do
      echo -ne "\b\b\b\b»   "; sleep .5; echo -ne "\b\b\b\b»»  "; sleep .5
      echo -ne "\b\b\b\b»»» "; sleep .5; echo -ne "\b\b\b\b    "; sleep .5
  done
    }

    f_dores()
    {
  for S in $S
  do
      RESULTF=RESULTF$S RESULTFALIAS=$(eval alias RESULTF$S | cut -d "'" -f2) ; [ "$1" = "-a" ] && return
      RESULTF=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTF=$(echo $RESULTF)
      RESULTFC=$(echo $RESULTF|wc -w) ; [ "$1" = "-r" ] && return
      OBSOLETES=OBSOLETES$S; OBSOLETES=`echo ${!OBSOLETES}|mawk '{gsub("¿"," ");print $0}'`
      OBSOLETES=$(echo $OBSOLETES); OBSOLETESC=$(echo $OBSOLETES|wc -w)
  done
    }
    f_obs()
    {
  [ -n "$OBSOLETESTC" ] && return
  echo -n " [»] traitement     "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for S in $SOURCESN
  do
      f_dores -r; unset -v OBSOLETES
      for p in $RESULTF
      do
    grep -qxm 1 "Package: $p" $SOURCESDIR$RESULTFALIAS\
    || OBSOLETES="$OBSOLETES¿$p" OBSOLETEST="$OBSOLETEST $p"
      done
      eval OBSOLETES$S="$OBSOLETES"
  done
  OBSOLETEST=$(printf '%b\n' $OBSOLETEST|sort -u) OBSOLETESTC=$(echo $OBSOLETEST|wc -w)
  for o in $OBSOLETEST
  do
      unset -v COUNTER NOBS
      for S in $SOURCESN
      do
    f_dores -r
    let COUNTER++; [ $COUNTER -eq 1 ]\
    && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
    && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
    && OBSOLETESTR="$OBSOLETESTR $o"
    LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS); [ -z "$LOC" ] && continue
    LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
    VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
    [ "$VERI" = "$VER" ] && NOBS=1
      done
      [ -n "$NOBS" ] && OBSOLETESTR=$(printf '%b\n' $OBSOLETESTR|grep -vx $o)
  done
  OBSOLETESTRC=$(echo $OBSOLETESTR|wc -w); unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }
    f_twin()
    {
  [ -n "$TWIN" -o -n "$SINGLE" ] && return
  echo -n " [»] traitement     "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for u in $RESULTFTU
  do
      unset -v COUNTER
      for s in $RESULTFTS
      do
    [[ "$u" != "$s" ]] && continue
    let COUNTER++
      done
      [[ "$COUNTER" < 2 ]] && SINGLE="$SINGLE $u" && continue
      TWIN="$TWIN $u"
      TWINP="$TWINP $COUNTER"¿"$u"
  done
  TWINC=$(echo $TWIN|wc -w) SINGLEC=$(echo $SINGLE|wc -w)
  TWINP=`printf ' %b\n' $TWINP|sort -d|mawk '{gsub("¿","×  ");print $0}'`
  SINGLEP=$(printf ' [%b]' $SINGLE) ; TWIND=$(printf '%b\n' $TWIN)
  unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }

    f_displayg()
    {
  { echo; echo " [>] [$MACHINE] Occurrences globales:"; }|f_tee
  [ "$SOURCESG" = "" ] &&\
  for S in $SOURCESN;do f_dores -r;[ $RESULTFC -ne 0 ] && SOURCESG="$SOURCESG $RESULTFALIAS" && SOURCESNG="$SOURCESNG $S" && let SOURCESGC++
  done
  [ "$SOURCESG" = "" ] && { echo " [×] Aucune des sources analysées n'a d'occurrence installée sur $MACHINE"; echo -e "\n\n"; }|f_tee && return
  { echo " [»] $SOURCESGC sources analysées ont des occurrences installées sur $MACHINE:"; echo; }|f_tee
  for S in $SOURCESNG; do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"|f_tee; TTLOCC=$(($TTLOCC+$RESULTFC)); done
  f_obs
  NOSOURCEDC=$(($OBSOLETESTRC+$UNKNOWNC)) SOURCEDC=$(($RESULTFTUC-$OBSOLETESTRC))
  { echo " [*] total: $TTLOCC occurrences"; echo; echo " [*] $NINSTALLED paquets installés sur $MACHINE"
  echo " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés"
  echo " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées"
  echo " [*] dont $OBSOLETESTRC paquets obsolètes et $UNKNOWNC paquets d'origine inconnue"
  echo " [*] $SOURCEDC paquets installés présents dans les sources analysées:"; echo; }|f_tee ; unset -v TTLOCC
  f_pager
  [ "$SOURCEDP" = "" ] && SOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $RESULTFTU|sort -d|uniq -u))
  [ "$NOSOURCEDP" = "" ] && NOSOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $UNKNOWNS|sort -d))
  [ "$NOPURGEP" = "" ] && NOPURGEP=$(printf ' [%b]' $NOPURGE)
  [ $PAGER = L ] && { printf '\n%b\n' " [*] $SOURCEDC paquets installés présents dans les sources analysées:" "$SOURCEDP"|f_fmt
  [ $NOSOURCEDC -gt 0 ] && printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; }|f_tee |f_less
  [ $PAGER = d ] && { echo "$SOURCEDP"|f_fmt; [ $NOSOURCEDC -gt 0 ] &&\
  printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; } |f_tee
  [ $PAGER = n ] && echo -e "$PAGERM"|f_tee || echo -e "$PAGERM"; { echo ; echo; }|f_tee
  [ $TSOURCES -eq 1 ] && { [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo; } && return

  f_twin
  [ $TWINC -eq 0 ] && { echo " [×] aucun croisement d'occurrence de paquets installés sur $MACHINE entre les sources analysées"
  echo -e "\n\n"; }|f_tee && return
  { echo " [*] $SINGLEC occurrences uniques";echo " [*] $RESULTFTCC croisements d'occurrences";echo " [*] $TWINC occurrences croisées:"; }|f_tee
  f_pager
  [ $PAGER = L ] && { printf '\n%b\n%b\n\n%b' " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:" "$TWINP"
  printf '\n\n\n%b\n\n%b' " [*] $SINGLEC occurrences uniques:" "$SINGLEP"|f_fmt; }|f_tee |f_less && echo -e "\n$PAGERM"
  [ $PAGER = d ] && { echo -e "\n$TWINP";echo -e "\n";echo -e " [*] $SINGLEC occurrences uniques:\n";echo "$SINGLEP"|f_fmt; }|f_tee
  [ $PAGER = n ] && echo -e "\n$PAGERM"|f_tee
  [ $RECORD = 1 ] && echo -e "\n\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    f_display()
    {
  { echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo; }|f_tee
  { for (( S=1; S <= $TSOURCES; S++ )); do f_dores -r; echo $SELECTS|grep -w $S &>/dev/null
  [ $? -eq 0 ] && echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]" || echo " [×]";done; }|f_tee
  f_pager
  [ $PAGER != n  ] && f_obs &&\
  for S in $SELECTS
  do
      f_dores
      echo -e "\n [*] $RESULTFC occurrences installées présentes dans le cache de la source [$RESULTFALIAS]:"
      [ $RESULTFC -ne 0 ] && echo && printf ' [%b]' $RESULTF|f_fmt; echo
      [ $OBSOLETESC -ne 0 ] && echo " [*] dont $OBSOLETESC occurrences obsolètes:" && printf ' [%b]' $OBSOLETES|f_fmt && echo
  done |f_tee|f_less ; echo|f_tee
  [ $PAGER = n ] && echo -e "$PAGERM\n"|f_tee || echo -e "$PAGERM\n"; echo|f_tee
  { printf " [»] occurrences uniques et croisées des sources"; printf ' [%b]' $SELECTS; echo ":"; }|f_tee
  f_pager
  f_sort()
  {
      f_twin
      for S in $SELECTS
      do
    f_dores -r
    for r in $RESULTF
    do
        echo "$TWIND"|grep -qxm 1 "$r" &>/dev/null && MULTIX="$MULTIX $r" && continue
        UNIX="$UNIX $r"
    done
    UNIXC=$(echo $UNIX|wc -w) MULTIXC=$(echo $MULTIX|wc -w)
    echo -e "\n [$S] $RESULTFALIAS [$(($UNIXC+$MULTIXC)) occurrences]" ; echo
    [ $UNIXC -ne 0 ] && echo " [*] $UNIXC occurrences uniques:" && printf ' [%b]' $UNIX|f_fmt && echo
    [ $MULTIXC -ne 0 ] && echo " [*] $MULTIXC occurrences croisées:" && printf ' [%b]' $MULTIX|f_fmt && echo
    unset -v UNIX MULTIX
      done |f_tee |f_less ; echo -e "\n$PAGERM\n\n"
      [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo
  }
  [ $PAGER != n  ] && f_sort || echo -e "\n$PAGERM\n\n\n"|f_tee
    }
    f_displaym()
    {
  echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo
  for ((S=1;S<=TSOURCES;S++)); do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"; done; echo
  while true
  do
      read -p " [¿] afficher les occurrences pour $SOURCESNP (défaut &) <$SOURCESN>: " SELECTS
      case "$SELECTS" in
    q|Q) f_exit;;
    h)  less $0;;
    "") SELECTS=$SOURCESN ; $CLEAR ; f_display ; break;;
    *)  SELECTS=$(printf '%b\n' $SELECTS|sort -u) doit=1
        for s in $SELECTS; do echo $SOURCESN|grep -w $s &>/dev/null; [ $? -ne 0 ] && doit=0; done
        [ $doit -ne 0 ] && $CLEAR && f_display && break;;
      esac
  done
    }

    f_package()
    {
  { echo -e "\n [>] [$MACHINE] Analyse par paquets:\n"; echo " [»] analyse des occurrences croisées entre les sources analysées:"; }|f_tee
  f_twin
  f_x()
  {
      { echo " [*] $RESULTFTCC croisements d'occurrences"
      echo " [*] $TWINC occurrences croisées:"; echo; }|f_tee
      f_pager
      [ $PAGER = n  ] && echo -e "$PAGERM\n"|f_tee && return
      for x in $TWIN
      do
    [ -z "$COUNT" -a $PAGER = L ] && printf '%b\n%b\n\n'\
    " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:"
    let COUNT++; echo " [$COUNT] [$x]"; unset -v COUNTER
    for S in $SOURCESN
    do
        f_dores -r; let COUNTER++
        [ $COUNTER -eq 1 ]\
        && LOCI=$(grep -xnm 1 "Package: $x" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo -e " $VERI $STATI"\
        && for d in $(ls $CACHEDIR/.old/sources/.deleted/)
        do grep -qxm 1 "$x" $CACHEDIR/.old/sources/.deleted/$d && echo " présent dans la source supprimée $d"; done
        LOC=$(grep -xnm 1 "Package: $x" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $x && echo " obsolète dans $RESULTFALIAS"; true; } && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS"
    done
    echo
      done |f_tee |f_less ; unset -v COUNT COUNTER; echo -e "$PAGERM\n"
  }
  [ $TWINC -eq 0 ]&&echo -e " [×] aucun croisement d'occurrences de paquets installés sur $MACHINE entre les sources analysées\n"|f_tee||f_x

  echo -e "\n\n [»] analyse des paquets installés non présents dans les sources analysées:"|f_tee
  f_u()
  {
      echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { COUNT=0 TUNKNOWNS=$UNKNOWNS; [ $PAGER = L ] && echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"
      for u in $UNKNOWNS
      do
    unset -v COUNTER
    for d in $(ls $CACHEDIR/.old/sources/.deleted/)
    do
        grep -qxm 1 "$u" $CACHEDIR/.old/sources/.deleted/$d && { TUNKNOWNS=$(printf '%b\n' $TUNKNOWNS|grep -vx $u); let COUNTER++
        [ $COUNTER -eq 1 ] && { let COUNT++; echo -e "\n [$COUNT] [$u]"; }; echo " origine possible: source supprimée [$d]"; }
    done
   
      done
      [ $COUNT -gt 0 -a $COUNT -lt $UNKNOWNC ] && { echo -e \
      "\n [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $(($UNKNOWNC-$COUNT)) autres paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }\
      || { [ $COUNT -eq 0 ]&&echo " [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $UNKNOWNC paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }; }|f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $UNKNOWNC -eq 0 ] && echo -e " [×] aucun paquet d'origine inconnue installé sur $MACHINE\n"|f_tee || f_u

  echo -e "\n\n [»] analyse des occurrences obsolètes dans le cache des sources analysées:"|f_tee
  f_obs
  f_o()
  {
      echo " [*] $OBSOLETESTC occurrences obsolètes:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { OBS=$OBSOLETESTC; echo; [ $PAGER = L  ] && { echo " [*] $OBSOLETESTC occurrences obsolètes:"; echo; }
      for o in $OBSOLETEST
      do
    let COUNT++; unset -v COUNTER NOBS
    for S in $SOURCESN
    do
        f_dores -r
        let COUNTER++; [ $COUNTER -eq 1 ] && echo " [$COUNT] [$o]"\
        && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo " $VERI $STATI" && OBSR="$OBSR $o"
        LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $o && echo " obsolète dans $RESULTFALIAS"; true; }\
        && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS" ; [ "$VERI" = "$VER" ] && NOBS=1
    done
    [ -n "$NOBS" ] && { echo " [¡] la version installée de $o n'est PAS obsolète"; let OBS--; OBSR=$(printf '%b\n' $OBSR|grep -vx $o); }
    echo
      done
      [ $OBS -eq 0 ] && echo " [×] aucun des paquets installés sur $MACHINE n'est obsolète"\
      || { echo -e "\n [*] $OBS paquets installés sur $MACHINE sont obsolètes:"; printf ' [%b]' $OBSR|f_fmt; echo; }
      [ $UNKNOWNC -ne 0 ]\
      && echo " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes"
      } |f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $OBSOLETESTC -eq 0 ] && { echo " [×] aucune occurrence obsolète de paquets installés sur $MACHINE dans les sources analysées"
  [ $UNKNOWNC -ne 0 ] &&\
  echo -e " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes\n\n"; } |f_tee || f_o
  [ $RECORD = 1 ] && echo -e "\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    echo
    [ $TSOURCES -eq 0 -a $OCCLESS -eq 1 ]\
    && echo " [>] Aucune des sources traitées ne présente d'occurrence en concordance avec les paquets installés sur $MACHINE"\
    && echo " [»] aucune analyse à effectuer" && echo && read -s -n 1 -p " [-] valider pour continuer... " && f_clearline r 1 35 && return 2
    echo " __________________________________________________________________________"
    echo " [-] Enregistrer la prochaine séquence - Aide - Accueil - Quitter <r/h/w/q>" ; RECORD=0 REC=""
    while true
    do
  read -s -n 1 -p " [¿]$REC [$MACHINE]: Analyse globale - Par sources - Par paquets <g/s/p>: " SELECT
  f_clearline r 1 110
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; return; };;
      r) REC=" [R]" RECORD=1;echo -e "\n\n $(date)" >>$RECFILE;;
      g) $CLEAR; f_displayg;break;;
      s) $CLEAR; f_displaym;break;;
      p) $CLEAR; f_package;break;;
  esac
    done
    f_postproc
}

f_home()
{
    [ -d ~/.$PROGNAME/$(uname -n) ] || { $CLEAR; echo -e "\n [>] Initialisation de $PROGNAME\n"; MACHINE=$(uname -n)
    f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }
    [ -d ~/.$PROGNAME/_alternate ] || { mkdir -p ~/.$PROGNAME/_alternate/
    echo "Copiez ici les répertoires /var/lib/apt/lists/ et /var/lib/dpkg/ d'un système alternatif que vous souhaitez analyser"\
    > ~/.$PROGNAME/_alternate/readme.txt; }

    $CLEAR; echo -e "\n\n\n\n\n\n"
    for w in Advanced  Packaging Tool DIAGnostic
    do
  NL=$(echo ${#w}) NLA=$NL; echo -n " "
  for ((l=1;l<=NL;l++))
  do
      L=$(echo $w|cut -c $l); echo $L|grep -q [A-Z] && L="\033[1m$L\033[0m"
      for ((la=NLA;la>=0;la--))
      do
    for ((s=la;s>=1;s--)); do SPACE="$SPACE "; done
    echo -ne "$SPACE$L "; NSPACE=$(echo ${#SPACE})
    unset -v SPACE; sleep 0.01; [ $NSPACE -eq 0 ] && break
    for ((b=1;b<=NSPACE+2;b++)); do echo -ne "\b"; done
      done
      NLA=$(($NLA-1))
      let INTER++; for ((s=2;s<=INTER/2;s++)); do echo -n " "; done
  done
  echo; unset -v INTER
    done
    echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n [>] $PROGNAME"; echo

    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ] && { echo " [»] un système alternatif a été détecté"
    [ -w ~/.$PROGNAME/_alternate/lists/ -a -w ~/.$PROGNAME/_alternate/dpkg/ ]\
    || { echo -e "\a\n [!] la configuration alternative n'a pas les droits en écriture, sortie\n"; exit 1; }
    [[ $(ADM=~; dpkg --admindir=$ADM/.$PROGNAME/_alternate/dpkg/ -l 2>/dev/null) ]]\
    || { echo -e "\a\n [!] le répertoire ~/.$PROGNAME/_alternate/dpkg/ n'est pas une configuration valide pour dpkg, sortie\n"; exit 1; }
    read -p " [¿] nom du système: " MACHINE; f_clearline r 1 100
    MACHINE=$(echo $MACHINE|tr -d ".%$&|<>*\'\"# /\\" 2>/dev/null|tr "[A-Z]" "[a-z]"|sed 's/^-//')
    [ $(echo ${#MACHINE}) -gt 35 ] && echo " [!] $MACHINE: ce nom est déraisonnablement long..." && sleep 3 && f_clearline r 1 120 && return
    [ -d ~/.$PROGNAME/$MACHINE ] && echo " [!] $MACHINE: ce nom de système est déjà utilisé..." && sleep 3 && f_clearline r 1 100 && return
    read -s -n 1 -p " [¿] ce nom est-il correct: $MACHINE ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 100 && return
    $CLEAR; echo -e "\n [>] Initialisation du cache pour $MACHINE\n"; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }

    echo " [»] systèmes analysables:"
    echo " [1] $(uname -n)"; COUNTER=1 MACHINES=1 MACHINESP=1; unset -v MACHINESUP MACHINESUPP
    for m in $(ls ~/.$PROGNAME/)
    do
  [ "$m" = "$(uname -n)" -o "$m" = "_alternate" ] && continue; [ -d ~/.$PROGNAME/$m ] || continue
  let COUNTER++; alias $COUNTER=$m; MACHINES="$MACHINES $COUNTER" MACHINESP="$MACHINESP/$COUNTER"
  MACHINESUP="$MACHINESUP $COUNTER" MACHINESUPP="$MACHINESUPP/$COUNTER"; echo " [$COUNTER] $m"
    done
    echo; unset -v COUNTER; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    [ -n "$MACHINESUP" ] && MACHINESUPP=$(echo $MACHINESUPP|sed 's/^\///') &&\
    while true
    do
  read -s -n 1 -p " [¿] Sélectionner un système - Supprimer un système (défaut 1) <$MACHINESP/->: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      -)  read -s -n 1 -p " [¿] sélectionner un système pour SUPPRESSION <$MACHINESUPP>: " SELECTM; f_clearline r 1 100
    echo $MACHINESUP|grep -w $SELECTM &>/dev/null\
    && { read -s -n 1 -p " [¿] supprimer $(alias $SELECTM|cut -d "'" -f2) de $PROGNAME ? <o/N>: " DEL; f_clearline r 1 100
    [ "$DEL" = o ] && rm -fr ~/.$PROGNAME/$(alias $SELECTM|cut -d "'" -f2); unset -v DEL; return; };;
      ""|1) MACHINE=$(uname -n); break;;
      *)  echo $MACHINES|grep -w $SELECT &>/dev/null && MACHINE=$(alias $SELECT|cut -d "'" -f2) && break;;
  esac
    done || MACHINE=$(uname -n); for m in $MACHINESUP; do unalias $m &>/dev/null; done
    while true
    do
  read -s -n 1 -p " [¿] [$MACHINE]: travailler sur l'ensemble des sources ? <O/n>: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      o|O|"") $CLEAR; echo; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; OCCLESS=1; f_squeezecache; f_postproc; break;;
      n) $CLEAR; echo; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; f_selectsources; f_occm; f_squeezecache; f_postproc; break;;
  esac
    done
}

while true; do f_home; done


PS: heureusement que c'est pas du python parce que l'indentation est un peu aléatoire sur le forum :)

Dernière modification par nofun (23-06-2009 17:12:19)

Hors ligne

#2 25-04-2009 11:53:48

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

La version 0.1 n'est donc pas fonctionnelle: le cache est corrompu dans certaines circonstances.

À propos du cache: j'indique qu'il n'est pas mis à jour automatiquement, cependant il n'a pas besoin d'être mis à jour à chaque changement sur le système.

Hors ligne

#3 25-04-2009 12:33:18

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Ah yoooo ! nofun.

Qu'est-ce que tu veux dire pour le python et le forum..? L'alignement des phrases ?
Et si tu essayais quote, aurais-tu le même problème ?

Désolé de ne pas t'aider, je ne suis pas programmeur... roll
Mais ton invite à se joindre est tentante... cool

Donc, tu nous conseilles d'attendre une nouvelle version ?
On attend donc... voir un peu si tu restes bien collé au truc...

A bientôt donc, amitié, Joel

Edit : donc... donc... donc... comme un gong thibetain...
Rions un peu... en attendant la mort.
Hein Pierre ?

Dernière modification par smolski (25-04-2009 12:36:22)


"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#4 25-04-2009 18:25:39

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

smolski a écrit :

Ah yoooo ! nofun.


Salut smolski, merci pour ta réponse.

smolski a écrit :

Qu'est-ce que tu veux dire pour le python et le forum..? L'alignement des phrases ?


oui, le forum supprime parfois certaines tabulations, et en python l'indentation fait partie de la syntaxe. En bash c'est juste pour la clarté.

smolski a écrit :

Et si tu essayais quote, aurais-tu le même problème ?


je ne sais pas, j'ai utilisé code parce que ça me paraissait logique, et je ne suis pas sûr que quote active les ascenseurs. J'aurai l'occasion de tester.

smolski a écrit :

Désolé de ne pas t'aider, je ne suis pas programmeur... roll
Mais ton invite à se joindre est tentante... cool


tu peux toujours proposer des idées, si j'ai la compétence (et le temps) je tenterai la réalisation, sinon peut-être qu'un autre ici le fera. Tu peux aussi te rendre compte que quelque chose fonctionne mal et le signaler.

smolski a écrit :

Donc, tu nous conseilles d'attendre une nouvelle version ?
On attend donc... voir un peu si tu restes bien collé au truc...


au truc je resterai bien collé vu qu'il m'est utile. Tu peux tester la version 0.1, elle fera pas exploser ta machine, mais le cache a pour l'instant de forts risques de ne pas refléter la réalité après une mise à jour. Les résultats seront cependants justes tant qu'il n'y aura pas de màj du système (initialisation du cache, pas de mise à jour du cache). Il suffit de supprimer soit ~/.apt-diag soit ~/.apt-diag/nom_de_machine pour réinitialiser.

J'ai voulu utiliser diff pour des raisons de rapidité du script, mais une boucle for serait la bonne solution niveau fiabilité. Je pense que je vais utiliser diff pour extraire un pré-résultat et mettre deux boucles for derrière, à moins que je puisse faire quelque chose avec diff et awk.
Je ne sais pas trop quand je pourrai faire ça parce que pour moi la crise est terminée pour l'instant et j'aurai moins de temps libre.

A bientôt donc, amitié, Joel


À bientôt donc smile , merci

Hors ligne

#5 25-04-2009 19:14:04

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Tsop nofun !

OK, à demain pour des tests sur des "pc publics"... J'en ai 4 en attente de mise à jour justement...

Toutefois, je ne pourrai te retourner que du "ça marche / ça marche pas..." il me manque la compréhension de ce qui se passe, quand ça marche, quand ça marche pas...
Ca t'iras ?

A bientôt, amitié, Joel

"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#6 26-04-2009 09:55:19

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Salut !

Yop, il faut telecharger le : "un système de test ici" en cliquant sur ici. Yes ?
Le telegargement fini, qu'est-ce qu'on fait ?
Un premier répertoire apparait nommé apt..tar-1
On l'ouvre, et
Un second s'ouvre nommé /.
On l'ouvre et un troisième répertoire apparait nommé aptdiagtestsys

Wouap !

C'est le genre de truc que je ne pratique jamais... roll
Peux-tu faire un pas à pas numéroté et précis de A à Z ?

Amitié attentive, Joel

"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#7 26-04-2009 13:53:10

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

Salut,

smolski a écrit :

Toutefois, je ne pourrai te retourner que du "ça marche / ça marche pas..." il me manque la compréhension de ce qui se passe, quand ça marche, quand ça marche pas...
Ca t'iras ?


oui, bien sûr

Pour l'archive tar.bz2:

- aller dans le répertoire où l'archive a été téléchargée

tar -xvjf ./apt-diag_systeme-test.tar.bz2


(man tar)

- on obtient un répertoire appelé aptdiagtestsys (on peut le renommer si on veut, ça sera l'identifiant de la machine dans apt-diag)

- coller ce répertoire dans ~/.apt-diag/

- au prochain démarrage, apt-diag propose ce système à l'analyse

On peut aussi utiliser les fonctionnalités de Midnight Commander pour décompresser l'archive (se positionner sur l'archive, valider, copier le contenu).

Hors ligne

#8 26-04-2009 15:59:10

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

wouap...

Tout fait comme tu dis :
1/ telechargement de apt-diag_systeme-test.tar.bz2 dans tmp
sous root :
2/ tar -xvjf apt-diag_systeme-test.tar.bz2 avec le répertoire aptdiagtestsys dans mon home/user propriété root
sous root création de apt-diag dans la racine
mkdir /apt-diag
(tu avais mis un point (.) entre / et apt-diag ???). Avec le point, pas de répertoire de créé...

cp -r aptdiagtestsys /apt-diag
redémarrage... et y m'demande rien... Il y a quelque chose d'oublié ?
Désolé, je n'est vraiment pas l'habitude de tout ça...
Si tu fais marcher le bazar avec moi, sûr que nous aurons un tuto novice universelle ! big_smile

Amitié studieuse, Joel

"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#9 26-04-2009 17:03:53

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

smolski a écrit :

sous root :
2/ tar -xvjf apt-diag_systeme-test.tar.bz2 avec le répertoire aptdiagtestsys dans mon home/user propriété root


si tu utilises apt-diag en user, les fichiers doivent appartenir au user, donc le plus simple est de décompresser l'archive en user.

smolski a écrit :

sous root création de apt-diag dans la racine
mkdir /apt-diag
(tu avais mis un point (.) entre / et apt-diag ???). Avec le point, pas de répertoire de créé...


Tu n'as pas besoin de créer ~/.apt-diag, le script s'en charge. C'est même déconseillé de le faire manuellement, le script est conçu pour effectuer certaines opérations quand ce répertoire n'existe pas.
Au premier lancement, apt-diag crée les répertoires et fichiers dont il a besoin dans ~/.apt-diag, en particulier il initialise le cache pour la machine hôte. Ensuite tu peux coller le contenu de l'archive dans ~/.apt-diag et tu te retrouves avec deux systèmes analysables.
Le point devant un fichier ou un répertoire fait de celui-ci un fichier ou répertoire caché. Si tu ne le vois pas c'est que le logiciel que tu utilises les cache: il te faut activer quelque chose du genre «afficher les fichiers cachés». Avec ls il faut utiliser l'option -a:

ls -a


apt-diag cherche le répertoire ~/.apt-diag, pas ~/apt-diag

Hors ligne

#10 26-04-2009 17:14:10

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Ah ? Ok...
Donc, je supprime le répertoire /apt-daig et tout ce qu'il contient et je te redis...
Petit à petit, je pigel'ensemble...
A tout'

Edit.
J'ai désinstallé le répertoire, collé le répertoire idoïne dans celui des fichiers cachés... Il avait été créé précédemment...

Redémarrer, pas d'injonction apt-diag...

Par contre, le fichier installed de aptdiagttest est bien rempli...
Je vire tout et recommence ?

Tsop, Joel

Dernière modification par smolski (26-04-2009 17:56:52)


"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#11 26-04-2009 21:46:47

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

smolski a écrit :

J'ai désinstallé le répertoire, collé le répertoire idoïne dans celui des fichiers cachés... Il avait été créé précédemment...

Redémarrer, pas d'injonction apt-diag...

Par contre, le fichier installed de aptdiagttest est bien rempli...
Je vire tout et recommence ?


Il n'y a pas d'injonction, il te présente juste les systèmes analysables et tu peux sélectionner celui que tu veux:

[>] apt-diag

[»] systèmes analysables:
[1] ton_système
[2] aptdiagtestsys

[-] Aide - Accueil - Quitter <h/w/q>
[¿] Sélectionner un système - Supprimer un système (défaut 1) <1/2/->:

Ce n'est pas la peine de supprimer le fichier Installed, de toute façon il est automatiquement recréé.

Hors ligne

#12 26-04-2009 22:22:44

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

OK, donc, après la mise en route du pc,
écrire dans un terminal (sous root ?)
# apt-diag
pour lancer ton application, c'est ça ?
Et nous avons toutes les indications disponibles des paquets installés selon le système sélectionné. Yes ?

Ouf, je finirai les tests demain matin... Le soir, j'galère dans la cervelle, désolé...

Amitié, Joel

"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#13 26-04-2009 23:14:09

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

smolski a écrit :

OK, donc, après la mise en route du pc,


il est conseillé que la machine soit en fonctionnement smile

smolski a écrit :

écrire dans un terminal (sous root ?)


comme dit dans l'introduction en début de script, apt-diag fonctionne de la même manière en root et en user

smolski a écrit :

# apt-diag
pour lancer ton application, c'est ça ?


procédure complète pour ceux qui ne sont pas familiers:

- coller le texte complet du script dans un éditeur (Gedit, Kate, KEdit ou NEdit par exemple) et enregistrer sous le nom apt-diag
- donner les droits en exécution au script (chmod +x ./apt-diag)
- on peut lancer le script en donnant son chemin complet: /home/user/apt-diag par exemple ou en se mettant dans son répertoire et en l'appelant directement: ./apt-diag
- on peut placer le script dans /usr/local/bin/ pour pouvoir l'appeler directement (/usr/local/bin/ est dans le path). Dans ce cas, penser à changer le propriétaire à root (chown root:root ./apt-diag)

smolski a écrit :

Et nous avons toutes les indications disponibles des paquets installés selon le système sélectionné. Yes ?


oui, une vue synthétique des paquets installés avec analyse des paquets présents dans plusieurs sources, des paquets obsolètes et d'origine inconnue,... Ce script cherche à combler le manque de vision globale des paquets installés sur un système Debian et il aide à mieux l'administrer et à établir un diagnostic en cas de problème avec les paquets.

Hors ligne

#14 27-04-2009 07:31:56

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Bonjour,

Ca se décortique grave là !
Merci de ta patience, je pense que tout cela est un peu nécessaire, peut-être pourrons-nous tous deux supprimer les post digratoires de ce fil pour ne garder qu'un ensemble cohérent... non ?

Bon, j'ai ôté l'application apt-diag du sytème où elle était nichée afin de refaire une procédure dans le fil de ton dernier post...
J't'y dis aujourd'hui ce que je vais fabriquer et des résultats y afférents...

On n'est pas que des grenouilles... Hein ? Tchibâââ ! lol

Amitié vive, Joel

Tchop ! Edit : Désolé, pris par des bêtises de la vie... essais demain matin... a+ smile

Dernière modification par smolski (27-04-2009 20:23:58)


"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#15 30-04-2009 22:18:42

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

smolski a écrit :

peut-être pourrons-nous tous deux supprimer les post digratoires de ce fil pour ne garder qu'un ensemble cohérent... non ?


pas de problème, fais à ta guise, c'est toi le modo.

J'espère avoir du temps ce week-end pour corriger le problème de la version 0.1

@+

Hors ligne

#16 01-05-2009 01:54:29

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Tsop,

Du travail m'a pris le temps des essais.... Je pars tout le we.. teste après.... roll

Mais si il y en a un pour le faire aussi, pas de problème, le tuto est cool...

Pour les post, OK, nous verrons après les tests. wink

Amitié, Joel

"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#17 10-05-2009 01:23:30

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

v.0.2

#!/bin/bash

############                                                           #########
# apt-diag #                                                           # v.0.2 #
################################################################################
# author: (C)2009 nofun_AT_laposte_DOT_net ## bug report, suggestion, wishlist #
####################################################### are welcome ############
# GNU General Public License v.3 or later http://www.gnu.org/copyleft/gpl.html #
################################################################################
######## homepage: http://debian-facile.org/forum/viewtopic.php?id=1285 ########
################################################################################

# Changelog:

# v.0.1 (avril 2009):
# version initiale.

# v.0.2 (mai 2009):
# correction d'un bug dans la mise a jour du cache (f_updatecache).
# ajout de la presentation des derniers paquets ajoutes et supprimes depuis la
# derniere mise a jour du cache.

################################################################################

# apt-diag: pour que claires les sources demeurent

# apt-diag cherche a donner une vue d'ensemble des paquets installes sur un
# systeme utilisant apt (Advanced Packaging Tool du projet Debian).
# Il aide en particulier a determiner de quelle source peut provenir un paquet,
# indique quand c'est le cas la presence d'un meme paquet dans de multiples
# sources et dresse la liste des paquets n'appartenant plus a aucune source
# (ensemble des paquets obsoletes et des paquets de source inconnue).
# C'est un bon complement a 'apt-cache policy nom_du_paquet'.

# De plus, apt-diag maintient un cache personnel des paquets par source, ce qui
# lui permet d'etablir la liste des paquets obsoletes en provenance de chaque
# source, information sinon indisponible. Les sources supprimees sont egalement
# archivees. Le degre d'information que fournit apt-diag est donc dependant de
# la date d'initialisation du cache.

# apt-diag n'agit pas sur le systeme de gestion des paquets, il est donc su^r
# pour le systeme hote. Le seul appel au systeme de gestion des paquets est du
# type 'dpkg -l' ou 'dpkg --get-selections'. De ce fait, apt-diag peut analyser
# un systeme autre que le systeme hote si on lui fournit les repertoires
# /var/lib/apt/lists/ et /var/lib/dpkg/ d'un syteme alternatif et fonctionne
# parfaitement en simple utilisateur.
# apt-diag possede une fonctionnalite d'enregistrement des analyses dans un
# fichier, ce qui permet de conserver une trace ou de communiquer l'etat du
# systeme a un tiers.

# Limitations:
# tout diagnostic est faillible et sujet a des erreurs d'interpretation. Il
# appartient a l'administrateur d'evaluer les informations fournies par apt-diag
# en particulier en confrontant les resultats obtenus avec ceux que pourront lui
# procurer les outils systeme a sa disposition. La licence GNU GPL sous laquelle
# apt-diag est delivre n'offre aucune garantie de bon fonctionnement.
# apt-diag n'a pas (encore) ete teste en presence de downgrade ou d'apt-pinning
# et plus generalement demande a etre teste davantage.
# apt-diag n'est pas integre au systeme de gestion des paquets, de ce fait la
# mise a jour du cache n'est pas automatique lors de la mise a jour du systeme.
# apt-diag evalue les paquets par leur nom, l'evaluation par numero de version
# est embryonnaire et demanderait d'autres techniques de programmation.
# Si un paquet a ete installe depuis une source par la suite supprimee et que ce
# paquet apparait toujours dans une autre source avec une version inferieure,
# rien de particulier n'est signale au sujet de ce paquet par apt-diag.

# Merci de distribuer apt-diag avec le texte ci-dessus.
# Bonne utilisation.

################################################################################
PROGNAME=$(basename $0)

f_conv()
{
    #TestCharSet: aéèêîïà¿»×x
    grep -m 1 "TestCharSet:" $0 > /tmp/testcharset
    PRGCHARSET=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'|tr [a-z] [A-Z]`
    SYSCHARSET=$(locale charmap)
    ! echo $SYSCHARSET|grep -q $PRGCHARSET && echo -e "\n [>] Conversion de $PROGNAME de $PRGCHARSET vers $SYSCHARSET...\c"\
    && { iconv -f "$PRGCHARSET" -t "$SYSCHARSET"//TRANSLIT $0 -o /tmp/$PROGNAME && chmod +x /tmp/$PROGNAME\
    && grep -m 1 "TestCharSet:" /tmp/$PROGNAME > /tmp/testcharset && PRGCHARSETR=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'`\
    && { [ "$PRGCHARSET" = "$(echo $PRGCHARSETR|tr [a-z] [A-Z])" ] && echo " ok" || echo; } && rm -f /tmp/testcharset\
    && echo -e " [*] la version $PRGCHARSETR de $PROGNAME est disponible dans /tmp/$PROGNAME\n" && exit\
    || { echo -e "\a\n [!] un probleme est survenu pendant la conversion, sortie\n"; exit 1; }; }
}
[ -d ~/.$PROGNAME ] || { f_conv; [ -d /var/lib/apt/lists/ ] && [[ $(dpkg -l 2>/dev/null) ]]\
|| { echo -e "\a\n [!] $PROGNAME n'est pas compatible avec le système hôte, sortie\n"; exit 1; }; }

which bc &>/dev/null|| { echo -e "\a\n [>] $PROGNAME\n [!] Ce script nécessite bc pour fonctionner, veuillez l'installer:\n"
aptitude show bc; echo -e "\n [*] aptitude -(s)v install bc\n"; exit 1; }

[ "$1" = "-c" ] && ECHO=echo || CLEAR=clear ; hash grep mawk
grep -q "Ratio $(uname -n):" ~/.$PROGNAME/ratio 2&>/dev/null && RATIO=`grep "Ratio $(uname -n):" ~/.$PROGNAME/ratio|cut -d " " -f3`
################################################################################

f_clearline()
{
    [[ $1 = [br] ]] && [ -n "$3" ] && echo $2$3|grep -qx [0-9]* || return 1
    while true
    do
  local COUNTER; let COUNTER++ ; echo -ne "\\$1"
  [ $COUNTER = $2 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; echo -ne " "
  [ $COUNTER = $3 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; [ $1 = r ] && COUNTER=$3
  echo -ne "\\$1" ; [ $COUNTER = $3 ] && return
    done
}

f_exit() { read -s -n 1 -p " [¿] Quitter $PROGNAME ? <O/n>: " EXIT; [ "$EXIT" = n ] && f_clearline r 1 45 && return; echo; echo; exit; }

f_init()
{
    for (( s=1; s <= TSOURCES; s++ )); do unset -v RESULTF$s OBSOLETES$s; done
    unset -v DEL INEWS ISUPR NOPURGEP NOSOURCEDP OBSOLETES OBSOLETEST OBSOLETESTC OBSOLETESTR
    unset -v RESULTF RESULTFT SINGLE SOURCEDP SOURCESG SOURCESGC SOURCESN SOURCESNG TSOURCES TWIN TWINP

    CACHEDIR=~/.$PROGNAME/$MACHINE/cache ; RECFILE=~/$PROGNAME\_$MACHINE\-$(date +%Y%m%d-%H%M%S).txt
    [ -d $CACHEDIR ] || {  mkdir -p $CACHEDIR/.old/sources/.deleted/ $CACHEDIR/sources/
    echo "$MACHINE $(date "+%F %T") initialisation du cache" >> ~/.$PROGNAME/$MACHINE/history.txt; }
    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ]\
    && mv -f ~/.$PROGNAME/_alternate/lists/ ~/.$PROGNAME/_alternate/dpkg/ ~/.$PROGNAME/$MACHINE/
    [ "$MACHINE" = "$(uname -n)" ] && SOURCESDIR=/var/lib/apt/lists/ INSTALLDIR=/var/lib/dpkg/\
    || SOURCESDIR=~/.$PROGNAME/$MACHINE/lists/ INSTALLDIR=~/.$PROGNAME/$MACHINE/dpkg/

    ## extraction de la liste des paquets installes sur le systeme
    INSTALLED=$(dpkg --admindir=$INSTALLDIR --get-selections |grep -w "install$" |mawk '{print $1}' |sort -d)
    NINSTALLED=$(echo $INSTALLED | wc -w)
    ## extraction et nettoyage des sources
    SOURCES=$(ls $SOURCESDIR |grep -vx lock |grep -vx partial)
    for a in _source_Sources i18n_Translation .ed$
    do
  SOURCES=$(printf '%b\n' $SOURCES | grep -v $a)
    done
    for s in $SOURCES
    do
  grep -qm 1 "^Package: " $SOURCESDIR$s || continue
  SOURCESC="$SOURCESC $s" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v SOURCESC
    echo " [»] Paquets installés: $INSTALLDIR Paquets disponibles: $SOURCESDIR"
    echo " [»] $NINSTALLED paquets installés sur $MACHINE"
}

f_progress()
{
    let PROGRESS++
    [ $PROGRESS = $ALPHAPROGRESS ] && echo -ne "\b-" && return
    [ $PROGRESS = $ALPHAPROGRESS2 ] && echo -ne "\b\\" && return
    [ $PROGRESS = $ALPHAPROGRESS3 ] && echo -ne "\b|" && return
    [ $PROGRESS = $ALPHAPROGRESS4 ] && echo -ne "\b/" && PROGRESS=0
}
f_adv()
{
    trap 'break' SIGUSR1
    while true
    do
  echo -ne "\b\b\b\b.   "; sleep .5; echo -ne "\b\b\b\b..  "; sleep .5
  echo -ne "\b\b\b\b... "; sleep .5; echo -ne "\b\b\b\b    "; sleep .5
    done
}

f_benchmachine()
{
    local ALPHAPROGRESS ALPHAPROGRESS2 ALPHAPROGRESS3 ALPHAPROGRESS4 BURN COUNTER PROGRESS SAMPLE SAMPLEb TEMPS TEMPS1 TEMPS2
    ALPHAPROGRESS=60 SAMPLE="sourceinstalled" # ! la taille du mot est importante ! ne pas modifier ! SAMPLE="sourceinstalled"
    ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
    f_burn()
    {
  CLOCKD=$(date +%s%N)
  while true
  do
      let COUNTER++; f_progress
      while true
      do
          let COUNTERb++; f_progress
          SAMPLEb="$SAMPLEb $(echo "$SAMPLE ")"
          [ $COUNTERb = 100 ] && break
      done
      unset -v COUNTERb
      echo $SAMPLEb|grep $SAMPLE|wc -w &>/dev/null
      [ $COUNTER = 10 ] && break
  done
  CLOCKF=$(date +%s%N)
  let BURN++
    }
    [ "$BURN" = "" ] && echo -n " [>] Benchmarking machine...  " && f_burn
    [ "$BURN" = "1" ] && unset -v COUNTER SAMPLEb && f_burn
    [ "$BURN" = "2" ] && TEMPS1=$(($CLOCKF-$CLOCKD)) && unset -v COUNTER SAMPLEb && f_burn
    TEMPS2=$(($CLOCKF-$CLOCKD)) TEMPS=$(($TEMPS1+$TEMPS2))
    RATIO=$(echo "scale=20;$TEMPS/2/$COUNTER/240000000"|bc|mawk '{printf "%0.1f\n",$1}')
    ## ($RATIO=1 est obtenu sur mon portable Core2Duo T7250 2GHz 2Go RAM, $RATIO>1 sur une machine plus lente)
    ## le resultat peut etre faux sur un portable non branche ou si une autre application prend de la ressource
    echo "Ratio $(uname -n): $RATIO" > ~/.$PROGNAME/ratio
    f_clearline r 1 35
}

f_benchmark()
{
    [ -z "$RATIO" ] && f_benchmachine; echo -n " [>] Benchmarking...  "; local RESULTF PROGRESS COUNTER
    ## ALPHACOUNTER: determine un nombre de boucles proportionnellement inverse au nombre de paquets dans la source pondere par le ratio machine
    ## destine a adapter le temps de bench en prenant en compte $NPA et la vitesse de la machine
    PREALPHACOUNT=`echo "scale=20;1/$NPA*150000*1/(1/$NPA*(300+$NPA/2))*1.8"|bc`
    ALPHACOUNTER=`echo "scale=20;$PREALPHACOUNT/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
    [ `echo "scale=0; $ALPHACOUNTER<2"|bc` -eq 1 ] && ALPHACOUNTER=2
    CLOCKD=$(date +%s%N)
    for i in $INSTALLED
    do
  let COUNTER++; f_progress
  RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $i)"
  [ $COUNTER -eq $ALPHACOUNTER ] && break
    done
    CLOCKF=$(date +%s%N)
    TEMPS=$(($CLOCKF-$CLOCKD)) BENCHMASS=$(($NPA*$COUNTER)) BENCH=$(echo "scale=10;$TEMPS/$BENCHMASS"|bc)
    f_clearline r 1 30
}

f_estimate()
{
    ESTIMATE=$(echo "scale=10;$BENCH*$COMPUTEMASS"|bc)
    ESTIMATEHS=$(echo "scale=0;$ESTIMATE/1000000000"|bc)
    ESTIMATEHSBC=$(echo "scale=3;$ESTIMATE/1000000000"|bc)
    mn=0 ss=$ESTIMATEHS ms=$(echo "$ESTIMATEHSBC-$ss"|bc|cut -d '.' -f2)
    [ $ESTIMATEHS -gt 59 ] && mn=$(($ESTIMATEHS/60)) && ss=$(($ss-$mn*60))
    [ $ss -lt 10 ] && ss="0$ss"
    ESTIMATE=$(echo ""$mn"m"$ss"s"$ms"ms")
}

f_mkcache()
{
    trap 'jobs -p f_adv &>/dev/null && kill $(jobs -p f_adv); echo -e \
    "\a\n$PROGNAME > WARNING! The disk cache might be left in an inconsistent state!"; f_exit' 2 3 9 15
    ## determine s'il y a des nouvelles sources a traiter:
    for s in $SOURCES; do [ -f $CACHEDIR/sources/$s ] && continue; SOURCESNEWS="$SOURCESNEWS $s"; let TSOURCESM++; done
    ## determine si des sources ont ete desactivees, dans ce cas les archive:
    ## NB: les depots designes par les noms de code des versions (ex. lenny) seront archives au changement de version,
    ## ceux utilisant la terminologie stable, testing, unstable,... seront traites par f_updatecache
    for s in $(ls $CACHEDIR/sources/)
    do
  printf '%b\n' $SOURCES|grep -qxm 1 $s &>/dev/null || { mv -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/.deleted/$s; DEL="$DEL $s"; }
    done
    [ -n "$DEL" ] && echo && for d in $DEL; do echo " [>] Archivage de la source supprimée $d";\
    echo "$MACHINE $(date "+%F %T") source supprimée $d archivée" >> ~/.$PROGNAME/$MACHINE/history.txt; done
    [ -z "$TSOURCESM" -a -n "$DEL" ] && { unset -v DEL; echo; echo >> ~/.$PROGNAME/$MACHINE/history.txt
    read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR; return; }; [ -z "$TSOURCESM" ] && return
    echo
    echo " [>] Création du cache initial de paquets installés pour les nouvelles sources:"; echo
    time\
    for a in $SOURCESNEWS
    do
  ## supprime la source du repertoire .deleted si elle a ete reactivee
  [ -f $CACHEDIR/.old/sources/.deleted/$a ] && rm -f $CACHEDIR/.old/sources/.deleted/$a
  ## ecrit dans $CACHEDIR/sources/$a les noms des paquets installes qui ont une occurrence dans $SOURCESDIR$a
  local TIMEFORMAT=" »»»  réelle: %lR" PROGRESS CSOURCES; let CSOURCES++
  echo " [»] Traitement de la source ($CSOURCES/$TSOURCESM) $a"
  PRERESULT=$(grep "^Package: " $SOURCESDIR$a | mawk '{print $2}') NPA=$(echo $PRERESULT | wc -w) COMPUTEMASS=$(($NPA*$NINSTALLED))
  echo " [»] $NPA paquets dans la source, $NINSTALLED paquets installés sur $MACHINE"
  [ -z "$RATIO" ] && f_benchmachine
  ### ALPHAPROGRESS: alteration proportionnelle de l'indicateur de progresssion. Utilise le nombre inverse de $NPA, pondere par $RATIO
  PREALPHAPROG=`echo "scale=20;1/$NPA*(200+$NPA)*10"|bc`
  [ `echo "scale=20; $PREALPHAPROG<=11"|bc` -eq 1 ]\
  && ALPHAPROGRESS=`echo "scale=20;(($PREALPHAPROG-10)*10+$PREALPHAPROG-10)/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`\
  || ALPHAPROGRESS=`echo "scale=20;$PREALPHAPROG/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS<1"|bc` -eq 1 ] && ALPHAPROGRESS=1
  [ `echo "scale=0; $ALPHAPROGRESS>20"|bc` -eq 1 ] &&\
  ALPHAPROGRESS=`echo "scale=20;20+(-1/$ALPHAPROGRESS+$ALPHAPROGRESS)/$NPA/1*$NPA/10"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS>30"|bc` -eq 1 ] && ALPHAPROGRESS=30
  ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
  f_benchmark
  f_estimate
  [ "$ESTIMATEHS" -lt 120 ] && echo -n " [»] durée estimée de traitement: $ESTIMATE  "\
  || echo -n " [»] durée estimée de traitement: $ESTIMATE (début $(date +%T))  "
  time\
  for WORKAROUND in 1
  do
      for b in $INSTALLED
      do
    f_progress
    RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $b)"
      done
      f_clearline b 1 1
  done
  printf '%b\n' $RESULTF|sort -d > $CACHEDIR/sources/$a
  echo "$MACHINE $(date "+%F %T") nouvelle source $a ajoutée" >>~/.$PROGNAME/$MACHINE/history.txt
  RESULTFC=$(echo $RESULTF | wc -w)
  [ $RESULTFC -ne 0 ] && echo " [*] $RESULTFC occurrences" || echo " [×] pas d'occurrence"
  echo ; unset -v PROGRESS RESULTF
  [ $TSOURCESM = $CSOURCES ] && local TIMEFORMAT=" [»] durée totale de traitement: %lR" && unset -v DEL SOURCESNEWS TSOURCESM
    done
    echo >>~/.$PROGNAME/$MACHINE/history.txt; echo; echo; read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR
}

f_updatecache()
{
    mv -f $CACHEDIR/Installed $CACHEDIR/.old/ 2>/dev/null; printf '%b\n' $INSTALLED > $CACHEDIR/Installed
    [ -f $CACHEDIR/.old/Installed ] || return
    ICHGE=$(echo $(diff -y --suppress-common-lines $CACHEDIR/.old/Installed $CACHEDIR/Installed))
    echo $ICHGE|grep -q "<" && ICHGE=`echo $ICHGE|mawk '{gsub("<","");print $0}'`
    echo $ICHGE|grep -q ">" && ICHGE=`echo $ICHGE|mawk '{gsub(">","");print $0}'`
    echo $ICHGE|grep -q "|" && ICHGE=`echo $ICHGE|mawk '{gsub("\|","");print $0}'`
    [ -z "$ICHGE" ] && return
    echo -e "\n [>] Mise à jour du cache    \c"; f_adv &
    for i in $ICHGE
    do
  grep -qx $i $CACHEDIR/Installed && INEWS="$INEWS $i" || ISUPR="$ISUPR $i"
    done
    [ -z "$ISUPR" -a -z "$INEWS" ] && { jobs -p f_adv &>/dev/null && kill -s SIGUSR1 $(jobs -p f_adv); } && return
    [ -n "$INEWS" ] && printf '%b\n' $INEWS > $CACHEDIR/Linews; [ -n "$ISUPR" ] && printf '%b\n' $ISUPR > $CACHEDIR/Lisupr

    mv -f $CACHEDIR/sources/* $CACHEDIR/.old/sources/ 2>/dev/null
    for s in $(ls $CACHEDIR/.old/sources/)
    do
  ## supprime du cache les occurrences desinstallees
  for r in $ISUPR
  do
      grep -vx "$r" $CACHEDIR/.old/sources/$s > $CACHEDIR/sources/$s && cp -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/$s
  done
  PRERESULT=$(grep "^Package: " $SOURCESDIR$s | mawk '{print $2}')
  cp -uf $CACHEDIR/.old/sources/$s $CACHEDIR/sources/$s
  ## ajoute au cache les nouvelles occurrences installees si elles apparaissent dans la source sauf si elles y sont deja
  for n in $INEWS
  do
      grep -qxm 1 "$n" $CACHEDIR/sources/$s &>/dev/null && continue
      echo "$PRERESULT"|grep -xm 1 "$n" >> $CACHEDIR/sources/$s
  done
  printf '%b\n' $(echo $(sort -d $CACHEDIR/sources/$s)) > $CACHEDIR/sources/$s
    done
    rm -f $CACHEDIR/.old/sources/* 2>/dev/null; jobs -p f_adv &>/dev/null && kill -s SIGUSR1 $(jobs -p f_adv); f_clearline r 1 35
    ## il est a noter que les paquets obsoletes (plus presents dans les sources) sont conserves dans le cache et analysables comme obsoletes
}

f_selectsources()
{
    unset -v RESUME TSOURCES
    ## formatage des sources pour la presentation, comptage des sources, presentation
    for a in $SOURCES
    do
  [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
  && SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}') $a"\
  || SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1}') $a"
  let TSOURCES++
    done
    [ -n "$ISUPR" -o -n "$INEWS" ] || echo; unset -v ISUPR INEWS
    echo " [>] $TSOURCES sources de paquets actuellement sélectionnées pour analyse:"
    echo ; unset -v TSOURCES
    printf ' [%b]\t» %b\n' $SOURCESP
    echo
    read -p " [¿] Sélectionner ou éliminer (préfixe «-») un motif pour filtrer, valider pour terminer: " MOTIF
    ## si le MOTIF est vide, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    [ "$MOTIF" = "" ] && SOURCESS=$SOURCES
    until [ "$MOTIF" = "" ]
    do
  MOTIFS="$MOTIFS $MOTIF"
  read -p " [¿] continuer la sélection des sources à analyser, valider pour terminer: " MOTIF
    done
    ## s'il n'y a que des eliminations, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    for m in $MOTIFS ; do MOTIFC="$(echo $m | cut -c 1) $MOTIFC" ; done
    MCM=$(printf '%b\n' $MOTIFC | grep -c "-") MC=$( printf '%b\n' $MOTIFC | grep -c "")
    [ "$MCM" = "$MC" ] && SOURCESS=$SOURCES
    ## boucle d'inclusion. La boucle interne permet de ne pas inclure une source deja presente (doublon)
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" != "-" ] && SELECT=$(printf '%b\n' $SOURCES | grep $MOTIF) || continue
  for s in $SELECT
  do
      [[ $(printf '%b\n' "$SOURCESS" | grep -w "$s") ]] && continue
      SOURCESS="$SOURCESS $s"
  done
    done
    ## boucle d'exclusion
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" = "-" ] && MOTIF=$(echo $MOTIF | cut -c 2-) && SOURCESS=$(printf '%b\n' $SOURCESS | grep -v $MOTIF)
    done
    SOURCES=$SOURCESS
    echo
    ## exclusion des fichiers qui ne sont pas des descripteurs de paquets
    echo " [>] Analyse des sources:"
    [ "$SOURCES" != "" ] && NSOURCES=$(printf '%b\n' $SOURCES | grep -c "") || NSOURCES=0
    for a in $SOURCES
    do
  if ! grep -qm 1 "^Package: " $SOURCESDIR$a
  then
      [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
      && b=$(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}')\
      || b=$(ls -sh $SOURCESDIR$a | mawk '{print $1}')
      echo " [×] non pertinente: $a [$b]"
      continue
  fi
  SOURCESC="$SOURCESC $a" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v MOTIFC MOTIFS SOURCESC SOURCESP SOURCESS
    [ "$SOURCES" = "" ] && TSOURCES=0
    [ "$TSOURCES" != "0" ]\
    && SOURCES=$(printf '%b\n' $SOURCES|sort -d) SOURCES=$(echo $SOURCES)\
    && echo " [»] $TSOURCES sources sur $NSOURCES à traiter dans la sélection:" && printf ' [*] [%b]\n' $SOURCES\
    || echo " [»] pas de sources à traiter dans la sélection"
    echo
    while true; do let COUNT++; echo ${FUNCNAME[$COUNT]}|grep -qx main && MAIN=$COUNT && unset -v COUNT && break; done
    RESUME=* ; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    while true
    do
  case "$RESUME" in
      q|Q) f_exit; RESUME=*;;
      h)  less $0; RESUME=*;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break $MAIN; };;
      p)  [ "$TSOURCES" != "0" ] && $CLEAR && f_selectsources || RESUME=r;;
      l|L|"") [ "$TSOURCES" != "0" ] && break || [ "$RESUME" = "" ] && RESUME=r || RESUME=*;;
      r|R) $CLEAR; f_init; f_selectsources;;
      *)  [ "$TSOURCES" != "0" ]\
    && read -s -n 1 -p " [¿] Préciser encore la sélection - Recommencer - Lancer l'analyse <p/r/L>: " RESUME\
    && f_clearline r 1 104
    [ "$TSOURCES" = "0" ] && read -s -n 1 -p " [¿] Recommencer <R>: " RESUME && f_clearline r 1 50;;
  esac
    done
}

f_occm()
{
    while true
    do
  read -s -n 1 -p " [¿] Par la suite traiter aussi les sources sans occurrences ? <o/N>: " SELECT
  f_clearline r 1 75
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break 2; };;
      o|O)  OCCLESS=0 ; unset -v SELECT ; $CLEAR ; break;;
      n|N|"") OCCLESS=1 ; unset -v SELECT ; $CLEAR ; break;;
  esac
    done
}

f_squeezecache()
{
    echo
    for s in $SOURCES
    do
  local CSOURCES CSOURCESM CSOURCESS ; let CSOURCES++ ; let CSOURCESS++
  RESULTF=$(cat $CACHEDIR/sources/$s) RESULTFC=$(echo $RESULTF | wc -w)
  ## eval interprete l'item suivant dans la liste comme une commande s'il y a un espace
  RESULTF=`echo $RESULTF|mawk '{gsub(" ","¿");print $0}'`
  ## attribution d'une variable dynamique au resultat individuel - utilisation de eval
  ## identification par le n° de traitement $CSOURCES, attribution du contenu de RESULTF a la nouvelle variable
  ## la nouvelle variable recoit le nom de la source en alias, permet la concordance n°/nom
  [ $RESULTFC -ne 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [*] $RESULTFC occurrences\t$s"
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [×] pas d'occurrence\t$s" && let CSOURCESM++
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 1 ] && let CSOURCES-- && echo -e " [×] pas d'occurrence\t$s"
  unset -v RESULTF
    done
    echo ; TSOURCES=$CSOURCES ; [ -z $CSOURCESM ] && CSOURCESM=0
    echo " [»] $(($CSOURCES - $CSOURCESM)) sources sur $CSOURCESS présentent des occurrences de paquets installés sur $MACHINE"
    echo ; unset -v CSOURCESM CSOURCESS CSOURCES
    ## concatenation des resultats individuels - utilisation de la substitution de variable {!RESULTF}
    for (( n=1; n <= TSOURCES; n++ ))
    do
  RESULTF=RESULTF$n ## RESULTF se substitue a la variable dynamique dont le contenu est appele par {!RESULTF}
  RESULTFP=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTFP=$(echo $RESULTFP)
  RESULTFT="$RESULTFT $RESULTFP" ## concatenation, doublons compris elimines par sort -u par la suite
  SOURCESN="$SOURCESN $n" ## extrait les numeros des sources disponibles de 1 a n sources
    done
    SOURCESN=$(echo $SOURCESN) SOURCESNP=`echo $SOURCESN|mawk '{gsub(" ","\&|");print $0}'`
    RESULTFTS=$(printf '%b\n' $RESULTFT | sort -d) RESULTFTU=$(echo $(printf '%b\n' $RESULTFT | sort -u))
    RESULTFTC=$(echo $RESULTFT|wc -w) RESULTFTUC=$(echo $RESULTFTU|wc -w) RESULTFTCC=$(($RESULTFTC-$RESULTFTUC))
    UNKNOWNS=$(printf '%b\n' $INSTALLED $RESULTFTU|sort -d|uniq -u) UNKNOWNC=$(echo $UNKNOWNS|wc -w)
    NOPURGE=`dpkg --admindir=$INSTALLDIR -l|grep "^rc "|mawk '{print $2}'` NOPURGEC=$(echo $NOPURGE|wc -w)
    LINEWSC=$(cat $CACHEDIR/Linews 2>/dev/null|wc -w); LISUPRC=$(cat $CACHEDIR/Lisupr 2>/dev/null|wc -w)
    LINEWS=$(printf ' [%b]' $(cat $CACHEDIR/Linews 2>/dev/null)) LISUPR=$(printf ' [%b]' $(cat $CACHEDIR/Lisupr 2>/dev/null))
    echo
    echo " [*] paquets installés sur $MACHINE: $NINSTALLED"
    echo " [*] occurrences installées sur $MACHINE: $RESULTFTUC"
    echo " [*] paquets installés non analysés: $(($NINSTALLED-$RESULTFTUC))"
    echo " [*] croisements d'occurrences: $RESULTFTCC"
    echo " [*] occurrences totales: $RESULTFTC"
    echo
}

f_postproc()
{
    f_fmt() { fmt -w $(tput cols); }
    f_tee() { [ $RECORD = 1 ] && tee -a $RECFILE || tee; }
    f_less() { [ $LESS = 1 ] && less -m~ || tee; }
    f_pager()
    {
  read -s -n 1 -p " [¿] afficher les occurrences avec Less - directement - ne pas afficher <L/d/n>: " PAGER
  f_clearline r 1 80 ; [ "$PAGER" = "d" -o "$PAGER" = "n" ] || PAGER=L ; PAGERM="\c"
  [ "$PAGER" = L ] && LESS=1 PAGERM="      [affichage dans le pager]" || LESS=0; [ "$PAGER" = n ] && PAGERM="      -------------------------"
    }

    f_dores()
    {
  for S in $S
  do
      RESULTF=RESULTF$S RESULTFALIAS=$(eval alias RESULTF$S | cut -d "'" -f2) ; [ "$1" = "-a" ] && return
      RESULTF=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTF=$(echo $RESULTF)
      RESULTFC=$(echo $RESULTF|wc -w) ; [ "$1" = "-r" ] && return
      OBSOLETES=OBSOLETES$S; OBSOLETES=`echo ${!OBSOLETES}|mawk '{gsub("¿"," ");print $0}'`
      OBSOLETES=$(echo $OBSOLETES); OBSOLETESC=$(echo $OBSOLETES|wc -w)
  done
    }
    f_obs()
    {
  [ -n "$OBSOLETESTC" ] && return
  echo -n " [»] traitement    "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for S in $SOURCESN
  do
      f_dores -r; unset -v OBSOLETES
      for p in $RESULTF
      do
    grep -qxm 1 "Package: $p" $SOURCESDIR$RESULTFALIAS\
    || OBSOLETES="$OBSOLETES¿$p" OBSOLETEST="$OBSOLETEST $p"
      done
      eval OBSOLETES$S="$OBSOLETES"
  done
  OBSOLETEST=$(printf '%b\n' $OBSOLETEST|sort -u) OBSOLETESTC=$(echo $OBSOLETEST|wc -w)
  for o in $OBSOLETEST
  do
      unset -v COUNTER NOBS
      for S in $SOURCESN
      do
    f_dores -r
    let COUNTER++; [ $COUNTER -eq 1 ]\
    && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
    && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
    && OBSOLETESTR="$OBSOLETESTR $o"
    LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS); [ -z "$LOC" ] && continue
    LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
    VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
    [ "$VERI" = "$VER" ] && NOBS=1
      done
      [ -n "$NOBS" ] && OBSOLETESTR=$(printf '%b\n' $OBSOLETESTR|grep -vx $o)
  done
  OBSOLETESTRC=$(echo $OBSOLETESTR|wc -w); unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }
    f_twin()
    {
  [ -n "$TWIN" -o -n "$SINGLE" ] && return
  echo -n " [»] traitement    "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for u in $RESULTFTU
  do
      unset -v COUNTER
      for s in $RESULTFTS
      do
    [[ "$u" != "$s" ]] && continue
    let COUNTER++
      done
      [[ "$COUNTER" < 2 ]] && SINGLE="$SINGLE $u" && continue
      TWIN="$TWIN $u"
      TWINP="$TWINP $COUNTER"¿"$u"
  done
  TWINC=$(echo $TWIN|wc -w) SINGLEC=$(echo $SINGLE|wc -w)
  TWINP=`printf ' %b\n' $TWINP|sort -d|mawk '{gsub("¿","×  ");print $0}'`
  SINGLEP=$(printf ' [%b]' $SINGLE) ; TWIND=$(printf '%b\n' $TWIN)
  unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }

    f_displayg()
    {
  { echo; echo " [>] [$MACHINE] Occurrences globales:"; }|f_tee
  [ "$SOURCESG" = "" ] &&\
  for S in $SOURCESN;do f_dores -r;[ $RESULTFC -ne 0 ] && SOURCESG="$SOURCESG $RESULTFALIAS" && SOURCESNG="$SOURCESNG $S" && let SOURCESGC++
  done
  [ "$SOURCESG" = "" ] && { echo " [×] Aucune des sources analysées n'a d'occurrence installée sur $MACHINE"; echo -e "\n\n"; }|f_tee && return
  { echo " [»] $SOURCESGC sources analysées ont des occurrences installées sur $MACHINE:"; echo; }|f_tee
  for S in $SOURCESNG; do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"|f_tee; TTLOCC=$(($TTLOCC+$RESULTFC)); done
  f_obs
  NOSOURCEDC=$(($OBSOLETESTRC+$UNKNOWNC)) SOURCEDC=$(($RESULTFTUC-$OBSOLETESTRC))
  { echo " [*] total: $TTLOCC occurrences"; echo; echo " [*] $NINSTALLED paquets installés sur $MACHINE"
  echo " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées"
  echo " [*] dont $OBSOLETESTRC paquets obsolètes et $UNKNOWNC paquets d'origine inconnue"
  echo " [*] $SOURCEDC paquets installés présents dans les sources analysées:"; echo; }|f_tee ; unset -v TTLOCC
  f_pager
  [ "$SOURCEDP" = "" ] && SOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $RESULTFTU|sort -d|uniq -u))
  [ "$NOSOURCEDP" = "" ] && NOSOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $UNKNOWNS|sort -d))
  [ "$NOPURGEP" = "" ] && NOPURGEP=$(printf ' [%b]' $NOPURGE)
  [ $PAGER = L ] && { printf '\n%b\n' " [*] $SOURCEDC paquets installés présents dans les sources analysées:" "$SOURCEDP"|f_fmt
  [ $NOSOURCEDC -gt 0 ] && printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $LINEWSC -gt 0 ] && printf '\n%b\n' \
  " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt
  [ $LISUPRC -gt 0 ] && printf '\n%b\n' \
  " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; }|f_tee |f_less
  [ $PAGER = d ] && { echo "$SOURCEDP"|f_fmt; [ $NOSOURCEDC -gt 0 ] &&\
  printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $LINEWSC -gt 0 ] && printf '\n%b\n' \
  " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt
  [ $LISUPRC -gt 0 ] && printf '\n%b\n' \
  " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; } |f_tee
  [ $PAGER = n ] && echo -e "$PAGERM"|f_tee || echo -e "$PAGERM"; { echo ; echo; }|f_tee
  [ $TSOURCES -eq 1 ] && { [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo; } && return

  f_twin
  [ $TWINC -eq 0 ] && { echo " [×] aucun croisement d'occurrence de paquets installés sur $MACHINE entre les sources analysées"
  echo -e "\n\n"; }|f_tee && return
  { echo " [*] $SINGLEC occurrences uniques";echo " [*] $RESULTFTCC croisements d'occurrences";echo " [*] $TWINC occurrences croisées:"; }|f_tee
  f_pager
  [ $PAGER = L ] && { printf '\n%b\n%b\n\n%b' " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:" "$TWINP"
  printf '\n\n\n%b\n\n%b' " [*] $SINGLEC occurrences uniques:" "$SINGLEP"|f_fmt; }|f_tee |f_less && echo -e "\n$PAGERM"
  [ $PAGER = d ] && { echo -e "\n$TWINP";echo -e "\n";echo -e " [*] $SINGLEC occurrences uniques:\n";echo "$SINGLEP"|f_fmt; }|f_tee
  [ $PAGER = n ] && echo -e "\n$PAGERM"|f_tee
  [ $RECORD = 1 ] && echo -e "\n\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    f_display()
    {
  { echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo; }|f_tee
  { for (( S=1; S <= $TSOURCES; S++ )); do f_dores -r; echo $SELECTS|grep -w $S &>/dev/null
  [ $? -eq 0 ] && echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]" || echo " [×]";done; }|f_tee
  f_pager
  [ $PAGER != n  ] && f_obs &&\
  for S in $SELECTS
  do
      f_dores
      echo -e "\n [*] $RESULTFC occurrences installées présentes dans le cache de la source [$RESULTFALIAS]:"
      [ $RESULTFC -ne 0 ] && echo && printf ' [%b]' $RESULTF|f_fmt; echo
      [ $OBSOLETESC -ne 0 ] && echo " [*] dont $OBSOLETESC occurrences obsolètes:" && printf ' [%b]' $OBSOLETES|f_fmt && echo
  done |f_tee|f_less ; echo|f_tee
  [ $PAGER = n ] && echo -e "$PAGERM\n"|f_tee || echo -e "$PAGERM\n"; echo|f_tee
  { printf " [»] occurrences uniques et croisées des sources"; printf ' [%b]' $SELECTS; echo ":"; }|f_tee
  f_pager
  f_sort()
  {
      f_twin
      for S in $SELECTS
      do
    f_dores -r
    for r in $RESULTF
    do
        echo "$TWIND"|grep -qxm 1 "$r" &>/dev/null && MULTIX="$MULTIX $r" && continue
        UNIX="$UNIX $r"
    done
    UNIXC=$(echo $UNIX|wc -w) MULTIXC=$(echo $MULTIX|wc -w)
    echo -e "\n [$S] $RESULTFALIAS [$(($UNIXC+$MULTIXC)) occurrences]" ; echo
    [ $UNIXC -ne 0 ] && echo " [*] $UNIXC occurrences uniques:" && printf ' [%b]' $UNIX|f_fmt && echo
    [ $MULTIXC -ne 0 ] && echo " [*] $MULTIXC occurrences croisées:" && printf ' [%b]' $MULTIX|f_fmt && echo
    unset -v UNIX MULTIX
      done |f_tee |f_less ; echo -e "\n$PAGERM\n\n"
      [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo
  }
  [ $PAGER != n  ] && f_sort || echo -e "\n$PAGERM\n\n\n"|f_tee
    }
    f_displaym()
    {
  echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo
  for ((S=1;S<=TSOURCES;S++)); do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"; done; echo
  while true
  do
      read -p " [¿] afficher les occurrences pour $SOURCESNP (défaut &) <$SOURCESN>: " SELECTS
      case "$SELECTS" in
    q|Q) f_exit;;
    h)  less $0;;
    "") SELECTS=$SOURCESN ; $CLEAR ; f_display ; break;;
    *)  SELECTS=$(printf '%b\n' $SELECTS|sort -u) doit=1
        for s in $SELECTS; do echo $SOURCESN|grep -w $s &>/dev/null; [ $? -ne 0 ] && doit=0; done
        [ $doit -ne 0 ] && $CLEAR && f_display && break;;
      esac
  done
    }

    f_package()
    {
  { echo -e "\n [>] [$MACHINE] Analyse par paquets:\n"; echo " [»] analyse des occurrences croisées entre les sources analysées:"; }|f_tee
  f_twin
  f_x()
  {
      { echo " [*] $RESULTFTCC croisements d'occurrences"
      echo " [*] $TWINC occurrences croisées:"; echo; }|f_tee
      f_pager
      [ $PAGER = n  ] && echo -e "$PAGERM\n"|f_tee && return
      for x in $TWIN
      do
    [ -z "$COUNT" -a $PAGER = L ] && printf '%b\n%b\n\n'\
    " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:"
    let COUNT++; echo " [$COUNT] [$x]"; unset -v COUNTER
    for S in $SOURCESN
    do
        f_dores -r; let COUNTER++
        [ $COUNTER -eq 1 ]\
        && LOCI=$(grep -xnm 1 "Package: $x" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo -e " $VERI $STATI"\
        && for d in $(ls $CACHEDIR/.old/sources/.deleted/)
        do grep -qxm 1 "$x" $CACHEDIR/.old/sources/.deleted/$d && echo " présent dans la source supprimée $d"; done
        LOC=$(grep -xnm 1 "Package: $x" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $x && echo " obsolète dans $RESULTFALIAS"; true; } && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS"
    done
    echo
      done |f_tee |f_less ; unset -v COUNT COUNTER; echo -e "$PAGERM\n"
  }
  [ $TWINC -eq 0 ]&&echo -e " [×] aucun croisement d'occurrences de paquets installés sur $MACHINE entre les sources analysées\n"|f_tee||f_x

  echo -e "\n\n [»] analyse des paquets installés non présents dans les sources analysées:"|f_tee
  f_u()
  {
      echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { COUNT=0 TUNKNOWNS=$UNKNOWNS; [ $PAGER = L ] && echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"
      for u in $UNKNOWNS
      do
    unset -v COUNTER
    for d in $(ls $CACHEDIR/.old/sources/.deleted/)
    do
        grep -qxm 1 "$u" $CACHEDIR/.old/sources/.deleted/$d && { TUNKNOWNS=$(printf '%b\n' $TUNKNOWNS|grep -vx $u); let COUNTER++
        [ $COUNTER -eq 1 ] && { let COUNT++; echo -e "\n [$COUNT] [$u]"; }; echo " origine possible: source supprimée [$d]"; }
    done
   
      done
      [ $COUNT -gt 0 -a $COUNT -lt $UNKNOWNC ] && { echo -e \
      "\n [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $(($UNKNOWNC-$COUNT)) autres paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }\
      || { [ $COUNT -eq 0 ]&&echo " [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $UNKNOWNC paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }; }|f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $UNKNOWNC -eq 0 ] && echo -e " [×] aucun paquet d'origine inconnue installé sur $MACHINE\n"|f_tee || f_u

  echo -e "\n\n [»] analyse des occurrences obsolètes dans le cache des sources analysées:"|f_tee
  f_obs
  f_o()
  {
      echo " [*] $OBSOLETESTC occurrences obsolètes:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { OBS=$OBSOLETESTC; echo; [ $PAGER = L  ] && { echo " [*] $OBSOLETESTC occurrences obsolètes:"; echo; }
      for o in $OBSOLETEST
      do
    let COUNT++; unset -v COUNTER NOBS
    for S in $SOURCESN
    do
        f_dores -r
        let COUNTER++; [ $COUNTER -eq 1 ] && echo " [$COUNT] [$o]"\
        && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo " $VERI $STATI" && OBSR="$OBSR $o"
        LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $o && echo " obsolète dans $RESULTFALIAS"; true; }\
        && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS" ; [ "$VERI" = "$VER" ] && NOBS=1
    done
    [ -n "$NOBS" ] && { echo " [¡] la version installée de $o n'est PAS obsolète"; let OBS--; OBSR=$(printf '%b\n' $OBSR|grep -vx $o); }
    echo
      done
      [ $OBS -eq 0 ] && echo " [×] aucun des paquets installés sur $MACHINE n'est obsolète"\
      || { echo -e "\n [*] $OBS paquets installés sur $MACHINE sont obsolètes:"; printf ' [%b]' $OBSR|f_fmt; echo; }
      [ $UNKNOWNC -ne 0 ]\
      && echo " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes"
      } |f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $OBSOLETESTC -eq 0 ] && { echo " [×] aucune occurrence obsolète de paquets installés sur $MACHINE dans les sources analysées"
  [ $UNKNOWNC -ne 0 ] &&\
  echo -e " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes\n\n"; } |f_tee || f_o
  [ $RECORD = 1 ] && echo -e "\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    echo
    [ $TSOURCES -eq 0 -a $OCCLESS -eq 1 ]\
    && echo " [>] Aucune des sources traitées ne présente d'occurrence en concordance avec les paquets installés sur $MACHINE"\
    && echo " [»] aucune analyse à effectuer" && echo && read -s -n 1 -p " [-] valider pour continuer... " && f_clearline r 1 35 && return 2
    echo " __________________________________________________________________________"
    echo " [-] Enregistrer la prochaine séquence - Aide - Accueil - Quitter <r/h/w/q>" ; RECORD=0 REC=""
    while true
    do
  read -s -n 1 -p " [¿]$REC [$MACHINE]: Analyse globale - Par sources - Par paquets <g/s/p>: " SELECT
  f_clearline r 1 110
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; return; };;
      r) REC=" [R]" RECORD=1;echo -e "\n\n $(date)" >>$RECFILE;;
      g) $CLEAR; f_displayg;break;;
      s) $CLEAR; f_displaym;break;;
      p) $CLEAR; f_package;break;;
  esac
    done
    f_postproc
}

f_home()
{
    [ -d ~/.$PROGNAME/$(uname -n) ] || { $CLEAR; echo -e "\n [>] Initialisation de $PROGNAME\n"; MACHINE=$(uname -n)
    f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }
    [ -d ~/.$PROGNAME/_alternate ] || { mkdir -p ~/.$PROGNAME/_alternate/
    echo "Copiez ici les répertoires /var/lib/apt/lists/ et /var/lib/dpkg/ d'un système alternatif que vous souhaitez analyser"\
    > ~/.$PROGNAME/_alternate/readme.txt; }

    $CLEAR; echo -e "\n\n\n\n\n\n"
    for w in Advanced  Packaging Tool DIAGnostic
    do
  NL=$(echo ${#w}) NLA=$NL; echo -n " "
  for ((l=1;l<=NL;l++))
  do
      L=$(echo $w|cut -c $l); echo $L|grep -q [A-Z] && L="\033[1m$L\033[0m"
      for ((la=NLA;la>=0;la--))
      do
    for ((s=la;s>=1;s--)); do SPACE="$SPACE "; done
    echo -ne "$SPACE$L "; NSPACE=$(echo ${#SPACE})
    unset -v SPACE; sleep 0.01; [ $NSPACE -eq 0 ] && break
    for ((b=1;b<=NSPACE+2;b++)); do echo -ne "\b"; done
      done
      NLA=$(($NLA-1))
      let INTER++; for ((s=2;s<=INTER/2;s++)); do echo -n " "; done
  done
  echo; unset -v INTER
    done
    echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n [>] $PROGNAME"; echo

    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ] && { echo " [»] un système alternatif a été détecté"
    [ -w ~/.$PROGNAME/_alternate/lists/ -a -w ~/.$PROGNAME/_alternate/dpkg/ ]\
    || { echo -e "\a\n [!] la configuration alternative n'a pas les droits en écriture, sortie\n"; exit 1; }
    [[ $(ADM=~; dpkg --admindir=$ADM/.$PROGNAME/_alternate/dpkg/ -l 2>/dev/null) ]]\
    || { echo -e "\a\n [!] le répertoire ~/.$PROGNAME/_alternate/dpkg/ n'est pas une configuration valide pour dpkg, sortie\n"; exit 1; }
    read -p " [¿] nom du système: " MACHINE; f_clearline r 1 100
    MACHINE=$(echo $MACHINE|tr -d ".%$&|<>*\'\"# /\\" 2>/dev/null|tr "[A-Z]" "[a-z]"|sed 's/^-//')
    [ $(echo ${#MACHINE}) -gt 35 ] && echo " [!] $MACHINE: ce nom est déraisonnablement long..." && sleep 3 && f_clearline r 1 120 && return
    [ -d ~/.$PROGNAME/$MACHINE ] && echo " [!] $MACHINE: ce nom de système est déjà utilisé..." && sleep 3 && f_clearline r 1 100 && return
    read -s -n 1 -p " [¿] ce nom est-il correct: $MACHINE ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 100 && return
    $CLEAR; echo -e "\n [>] Initialisation du cache pour $MACHINE\n"; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }

    echo " [»] systèmes analysables:"
    echo " [1] $(uname -n)"; COUNTER=1 MACHINES=1 MACHINESP=1; unset -v MACHINESUP MACHINESUPP
    for m in $(ls ~/.$PROGNAME/)
    do
  [ "$m" = "$(uname -n)" -o "$m" = "_alternate" ] && continue; [ -d ~/.$PROGNAME/$m ] || continue
  let COUNTER++; alias $COUNTER=$m; MACHINES="$MACHINES $COUNTER" MACHINESP="$MACHINESP/$COUNTER"
  MACHINESUP="$MACHINESUP $COUNTER" MACHINESUPP="$MACHINESUPP/$COUNTER"; echo " [$COUNTER] $m"
    done
    echo; unset -v COUNTER; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    [ -n "$MACHINESUP" ] && MACHINESUPP=$(echo $MACHINESUPP|sed 's/^\///') &&\
    while true
    do
  read -s -n 1 -p " [¿] Sélectionner un système - Supprimer un système (défaut 1) <$MACHINESP/->: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      -)  read -s -n 1 -p " [¿] sélectionner un système pour SUPPRESSION <$MACHINESUPP>: " SELECTM; f_clearline r 1 100
    echo $MACHINESUP|grep -w $SELECTM &>/dev/null\
    && { read -s -n 1 -p " [¿] supprimer $(alias $SELECTM|cut -d "'" -f2) de $PROGNAME ? <o/N>: " DEL; f_clearline r 1 100
    [ "$DEL" = o ] && rm -fr ~/.$PROGNAME/$(alias $SELECTM|cut -d "'" -f2); unset -v DEL; return; };;
      ""|1) MACHINE=$(uname -n); break;;
      *)  echo $MACHINES|grep -w $SELECT &>/dev/null && MACHINE=$(alias $SELECT|cut -d "'" -f2) && break;;
  esac
    done || MACHINE=$(uname -n); for m in $MACHINESUP; do unalias $m &>/dev/null; done
    while true
    do
  read -s -n 1 -p " [¿] [$MACHINE]: travailler sur l'ensemble des sources ? <O/n>: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      o|O|"") $CLEAR; echo; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; OCCLESS=1; f_squeezecache; f_postproc; break;;
      n) $CLEAR; echo; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; f_selectsources; f_occm; f_squeezecache; f_postproc; break;;
  esac
    done
}

while true; do f_home; done

Hors ligne

#18 21-06-2009 23:54:06

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

v.0.2a

cette version a été testée dans diverses situations et je n'ai pas rencontré de bug.

#!/bin/bash

############                                                          ##########
# apt-diag #                                                          # v.0.2a #
################################################################################
# author: (C)2009 nofun_AT_laposte_DOT_net ## bug report, suggestion, wishlist #
####################################################### are welcome ############
# GNU General Public License v.3 or later http://www.gnu.org/copyleft/gpl.html #
################################################################################
######## homepage: http://debian-facile.org/forum/viewtopic.php?id=1285 ########
################################################################################

# Changelog:

# v.0.1 (avril 2009):
# version initiale.

# v.0.2 (mai 2009):
# correction d'un bug dans la mise a jour du cache (f_updatecache).
# ajout de la presentation des derniers paquets ajoutes et supprimes depuis la
# derniere mise a jour du cache.

# v.0.2a (mai 2009):
# correction d'un bug dans la mise a jour du cache (f_updatecache).

################################################################################

# apt-diag: pour que claires les sources demeurent

# apt-diag cherche a donner une vue d'ensemble des paquets installes sur un
# systeme utilisant apt (Advanced Packaging Tool du projet Debian).
# Il aide en particulier a determiner de quelle source peut provenir un paquet,
# indique quand c'est le cas la presence d'un meme paquet dans de multiples
# sources et dresse la liste des paquets n'appartenant plus a aucune source
# (ensemble des paquets obsoletes et des paquets de source inconnue).
# C'est un bon complement a 'apt-cache policy nom_du_paquet'.

# De plus, apt-diag maintient un cache personnel des paquets par source, ce qui
# lui permet d'etablir la liste des paquets obsoletes en provenance de chaque
# source, information sinon indisponible. Les sources supprimees sont egalement
# archivees. Le degre d'information que fournit apt-diag est donc dependant de
# la date d'initialisation du cache.

# apt-diag n'agit pas sur le systeme de gestion des paquets, il est donc su^r
# pour le systeme hote. Le seul appel au systeme de gestion des paquets est du
# type 'dpkg -l' ou 'dpkg --get-selections'. De ce fait, apt-diag peut analyser
# un systeme autre que le systeme hote si on lui fournit les repertoires
# /var/lib/apt/lists/ et /var/lib/dpkg/ d'un syteme alternatif (a copier dans
# ~/.apt-diag/_alternate) et fonctionne parfaitement en simple utilisateur.
# apt-diag possede une fonctionnalite d'enregistrement des analyses dans un
# fichier, ce qui permet de conserver une trace ou de communiquer l'etat du
# systeme a un tiers.

# Limitations:
# tout diagnostic est faillible et sujet a des erreurs d'interpretation. Il
# appartient a l'administrateur d'evaluer les informations fournies par apt-diag
# en particulier en confrontant les resultats obtenus avec ceux que pourront lui
# procurer les outils systeme a sa disposition. La licence GNU GPL sous laquelle
# apt-diag est delivre n'offre aucune garantie de bon fonctionnement.
# apt-diag n'a pas (encore) ete teste en presence de downgrade ou d'apt-pinning
# et plus generalement demande a etre teste davantage.
# apt-diag n'est pas integre au systeme de gestion des paquets, de ce fait la
# mise a jour du cache n'est pas automatique lors de la mise a jour du systeme.
# apt-diag evalue les paquets par leur nom, l'evaluation par numero de version
# est embryonnaire et demanderait d'autres techniques de programmation.
# Si un paquet a ete installe depuis une source par la suite supprimee et que ce
# paquet apparait toujours dans une autre source avec une version inferieure,
# rien de particulier n'est signale au sujet de ce paquet par apt-diag.

# Merci de distribuer apt-diag avec le texte ci-dessus.
# Bonne utilisation.

################################################################################
PROGNAME=$(basename $0)

f_conv()
{
    #TestCharSet: aéèêîïà¿»×x
    grep -m 1 "TestCharSet:" $0 > /tmp/testcharset
    PRGCHARSET=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'|tr [a-z] [A-Z]`
    SYSCHARSET=$(locale charmap)
    ! echo $SYSCHARSET|grep -q $PRGCHARSET && echo -e "\n [>] Conversion de $PROGNAME de $PRGCHARSET vers $SYSCHARSET...\c"\
    && { iconv -f "$PRGCHARSET" -t "$SYSCHARSET"//TRANSLIT $0 -o /tmp/$PROGNAME && chmod +x /tmp/$PROGNAME\
    && grep -m 1 "TestCharSet:" /tmp/$PROGNAME > /tmp/testcharset && PRGCHARSETR=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'`\
    && { [ "$PRGCHARSET" = "$(echo $PRGCHARSETR|tr [a-z] [A-Z])" ] && echo " ok" || echo; } && rm -f /tmp/testcharset\
    && echo -e " [*] la version $PRGCHARSETR de $PROGNAME est disponible dans /tmp/$PROGNAME\n" && exit\
    || { echo -e "\a\n [!] un probleme est survenu pendant la conversion, sortie\n"; exit 1; }; }
}
[ -d ~/.$PROGNAME ] || { f_conv; [ -d /var/lib/apt/lists/ ] && [[ $(dpkg -l 2>/dev/null) ]]\
|| { echo -e "\a\n [!] $PROGNAME n'est pas compatible avec le système hôte, sortie\n"; exit 1; }; }

which bc &>/dev/null|| { echo -e "\a\n [>] $PROGNAME\n [!] Ce script nécessite bc pour fonctionner, veuillez l'installer:\n"
aptitude show bc; echo -e "\n [*] aptitude -(s)v install bc\n"; exit 1; }

[ "$1" = "-c" ] && ECHO=echo || CLEAR=clear ; hash grep mawk
grep -q "Ratio $(uname -n):" ~/.$PROGNAME/ratio 2&>/dev/null && RATIO=`grep "Ratio $(uname -n):" ~/.$PROGNAME/ratio|cut -d " " -f3`
################################################################################

f_clearline()
{
    [[ $1 = [br] ]] && [ -n "$3" ] && echo $2$3|grep -qx [0-9]* || return 1
    while true
    do
  local COUNTER; let COUNTER++ ; echo -ne "\\$1"
  [ $COUNTER = $2 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; echo -ne " "
  [ $COUNTER = $3 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; [ $1 = r ] && COUNTER=$3
  echo -ne "\\$1" ; [ $COUNTER = $3 ] && return
    done
}

f_exit() { read -s -n 1 -p " [¿] Quitter $PROGNAME ? <O/n>: " EXIT; [ "$EXIT" = n ] && f_clearline r 1 45 && return; echo; echo; exit; }

f_init()
{
    for (( s=1; s <= TSOURCES; s++ )); do unset -v RESULTF$s OBSOLETES$s; done
    unset -v DEL INEWS ISUPR NOPURGEP NOSOURCEDP OBSOLETES OBSOLETEST OBSOLETESTC OBSOLETESTR
    unset -v RESULTF RESULTFT SINGLE SOURCEDP SOURCESG SOURCESGC SOURCESN SOURCESNG TSOURCES TWIN TWINP

    CACHEDIR=~/.$PROGNAME/$MACHINE/cache ; RECFILE=~/$PROGNAME\_$MACHINE\-$(date +%Y%m%d-%H%M%S).txt
    [ -d $CACHEDIR ] || {  mkdir -p $CACHEDIR/.old/sources/.deleted/ $CACHEDIR/sources/
    echo "$MACHINE $(date "+%F %T") initialisation du cache" >> ~/.$PROGNAME/$MACHINE/history.txt; }
    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ]\
    && mv -f ~/.$PROGNAME/_alternate/lists/ ~/.$PROGNAME/_alternate/dpkg/ ~/.$PROGNAME/$MACHINE/
    [ "$MACHINE" = "$(uname -n)" ] && SOURCESDIR=/var/lib/apt/lists/ INSTALLDIR=/var/lib/dpkg/\
    || SOURCESDIR=~/.$PROGNAME/$MACHINE/lists/ INSTALLDIR=~/.$PROGNAME/$MACHINE/dpkg/

    ## extraction de la liste des paquets installes sur le systeme
    INSTALLED=$(dpkg --admindir=$INSTALLDIR --get-selections |grep -w "install$" |mawk '{print $1}' |sort -d)
    NINSTALLED=$(echo $INSTALLED | wc -w)
    ## extraction et nettoyage des sources
    SOURCES=$(ls $SOURCESDIR |grep -vx lock |grep -vx partial)
    for a in _source_Sources i18n_Translation .ed$
    do
  SOURCES=$(printf '%b\n' $SOURCES | grep -v $a)
    done
    for s in $SOURCES
    do
  grep -qm 1 "^Package: " $SOURCESDIR$s || continue
  SOURCESC="$SOURCESC $s" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v SOURCESC
    echo " [»] Paquets installés: $INSTALLDIR Paquets disponibles: $SOURCESDIR"
    echo " [»] $NINSTALLED paquets installés sur $MACHINE"
}

f_progress()
{
    let PROGRESS++
    [ $PROGRESS = $ALPHAPROGRESS ] && echo -ne "\b-" && return
    [ $PROGRESS = $ALPHAPROGRESS2 ] && echo -ne "\b\\" && return
    [ $PROGRESS = $ALPHAPROGRESS3 ] && echo -ne "\b|" && return
    [ $PROGRESS = $ALPHAPROGRESS4 ] && echo -ne "\b/" && PROGRESS=0
}
f_adv()
{
    trap 'break' SIGUSR1
    while true
    do
  echo -ne "\b\b\b\b.   "; sleep .5; echo -ne "\b\b\b\b..  "; sleep .5
  echo -ne "\b\b\b\b... "; sleep .5; echo -ne "\b\b\b\b    "; sleep .5
    done
}

f_benchmachine()
{
    local ALPHAPROGRESS ALPHAPROGRESS2 ALPHAPROGRESS3 ALPHAPROGRESS4 BURN COUNTER PROGRESS SAMPLE SAMPLEb TEMPS TEMPS1 TEMPS2
    ALPHAPROGRESS=60 SAMPLE="sourceinstalled" # ! la taille du mot est importante ! ne pas modifier ! SAMPLE="sourceinstalled"
    ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
    f_burn()
    {
  CLOCKD=$(date +%s%N)
  while true
  do
      let COUNTER++; f_progress
      while true
      do
          let COUNTERb++; f_progress
          SAMPLEb="$SAMPLEb $(echo "$SAMPLE ")"
          [ $COUNTERb = 100 ] && break
      done
      unset -v COUNTERb
      echo $SAMPLEb|grep $SAMPLE|wc -w &>/dev/null
      [ $COUNTER = 10 ] && break
  done
  CLOCKF=$(date +%s%N)
  let BURN++
    }
    [ "$BURN" = "" ] && echo -n " [>] Benchmarking machine...  " && f_burn
    [ "$BURN" = "1" ] && unset -v COUNTER SAMPLEb && f_burn
    [ "$BURN" = "2" ] && TEMPS1=$(($CLOCKF-$CLOCKD)) && unset -v COUNTER SAMPLEb && f_burn
    TEMPS2=$(($CLOCKF-$CLOCKD)) TEMPS=$(($TEMPS1+$TEMPS2))
    RATIO=$(echo "scale=20;$TEMPS/2/$COUNTER/240000000"|bc|mawk '{printf "%0.1f\n",$1}')
    ## ($RATIO=1 est obtenu sur mon portable Core2Duo T7250 2GHz 2Go RAM, $RATIO>1 sur une machine plus lente)
    ## le resultat peut etre faux sur un portable non branche ou si une autre application prend de la ressource
    echo "Ratio $(uname -n): $RATIO" > ~/.$PROGNAME/ratio
    f_clearline r 1 35
}

f_benchmark()
{
    [ -z "$RATIO" ] && f_benchmachine; echo -n " [>] Benchmarking...  "; local RESULTF PROGRESS COUNTER
    ## ALPHACOUNTER: determine un nombre de boucles proportionnellement inverse au nombre de paquets dans la source pondere par le ratio machine
    ## destine a adapter le temps de bench en prenant en compte $NPA et la vitesse de la machine
    PREALPHACOUNT=`echo "scale=20;1/$NPA*150000*1/(1/$NPA*(300+$NPA/2))*1.8"|bc`
    ALPHACOUNTER=`echo "scale=20;$PREALPHACOUNT/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
    [ `echo "scale=0; $ALPHACOUNTER<2"|bc` -eq 1 ] && ALPHACOUNTER=2
    CLOCKD=$(date +%s%N)
    for i in $INSTALLED
    do
  let COUNTER++; f_progress
  RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $i)"
  [ $COUNTER -eq $ALPHACOUNTER ] && break
    done
    CLOCKF=$(date +%s%N)
    TEMPS=$(($CLOCKF-$CLOCKD)) BENCHMASS=$(($NPA*$COUNTER)) BENCH=$(echo "scale=10;$TEMPS/$BENCHMASS"|bc)
    f_clearline r 1 30
}

f_estimate()
{
    ESTIMATE=$(echo "scale=10;$BENCH*$COMPUTEMASS"|bc)
    ESTIMATEHS=$(echo "scale=0;$ESTIMATE/1000000000"|bc)
    ESTIMATEHSBC=$(echo "scale=3;$ESTIMATE/1000000000"|bc)
    mn=0 ss=$ESTIMATEHS ms=$(echo "$ESTIMATEHSBC-$ss"|bc|cut -d '.' -f2)
    [ $ESTIMATEHS -gt 59 ] && mn=$(($ESTIMATEHS/60)) && ss=$(($ss-$mn*60))
    [ $ss -lt 10 ] && ss="0$ss"
    ESTIMATE=$(echo ""$mn"m"$ss"s"$ms"ms")
}

f_mkcache()
{
    trap 'jobs -p f_adv &>/dev/null && kill $(jobs -p f_adv); echo -e \
    "\a\n$PROGNAME > WARNING! The disk cache might be left in an inconsistent state!"; f_exit' 2 3 9 15
    ## determine s'il y a des nouvelles sources a traiter:
    for s in $SOURCES; do [ -f $CACHEDIR/sources/$s ] && continue; SOURCESNEWS="$SOURCESNEWS $s"; let TSOURCESM++; done
    ## determine si des sources ont ete desactivees, dans ce cas les archive:
    ## NB: les depots designes par les noms de code des versions (ex. lenny) seront archives au changement de version,
    ## ceux utilisant la terminologie stable, testing, unstable,... seront traites par f_updatecache
    for s in $(ls $CACHEDIR/sources/)
    do
  printf '%b\n' $SOURCES|grep -qxm 1 $s &>/dev/null || { mv -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/.deleted/$s; DEL="$DEL $s"; }
    done
    [ -n "$DEL" ] && echo && for d in $DEL; do echo " [>] Archivage de la source supprimée $d";\
    echo "$MACHINE $(date "+%F %T") source supprimée $d archivée" >> ~/.$PROGNAME/$MACHINE/history.txt; done
    [ -z "$TSOURCESM" -a -n "$DEL" ] && { unset -v DEL; echo; echo >> ~/.$PROGNAME/$MACHINE/history.txt
    read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR; return; }; [ -z "$TSOURCESM" ] && return
    echo
    echo " [>] Création du cache initial de paquets installés pour les nouvelles sources:"; echo
    time\
    for a in $SOURCESNEWS
    do
  ## supprime la source du repertoire .deleted si elle a ete reactivee
  [ -f $CACHEDIR/.old/sources/.deleted/$a ] && rm -f $CACHEDIR/.old/sources/.deleted/$a
  ## ecrit dans $CACHEDIR/sources/$a les noms des paquets installes qui ont une occurrence dans $SOURCESDIR$a
  local TIMEFORMAT=" »»»  réelle: %lR" PROGRESS CSOURCES; let CSOURCES++
  echo " [»] Traitement de la source ($CSOURCES/$TSOURCESM) $a"
  PRERESULT=$(grep "^Package: " $SOURCESDIR$a | mawk '{print $2}') NPA=$(echo $PRERESULT | wc -w) COMPUTEMASS=$(($NPA*$NINSTALLED))
  echo " [»] $NPA paquets dans la source, $NINSTALLED paquets installés sur $MACHINE"
  [ -z "$RATIO" ] && f_benchmachine
  ### ALPHAPROGRESS: alteration proportionnelle de l'indicateur de progresssion. Utilise le nombre inverse de $NPA, pondere par $RATIO
  PREALPHAPROG=`echo "scale=20;1/$NPA*(200+$NPA)*10"|bc`
  [ `echo "scale=20; $PREALPHAPROG<=11"|bc` -eq 1 ]\
  && ALPHAPROGRESS=`echo "scale=20;(($PREALPHAPROG-10)*10+$PREALPHAPROG-10)/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`\
  || ALPHAPROGRESS=`echo "scale=20;$PREALPHAPROG/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS<1"|bc` -eq 1 ] && ALPHAPROGRESS=1
  [ `echo "scale=0; $ALPHAPROGRESS>20"|bc` -eq 1 ] &&\
  ALPHAPROGRESS=`echo "scale=20;20+(-1/$ALPHAPROGRESS+$ALPHAPROGRESS)/$NPA/1*$NPA/10"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS>30"|bc` -eq 1 ] && ALPHAPROGRESS=30
  ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
  f_benchmark
  f_estimate
  [ "$ESTIMATEHS" -lt 120 ] && echo -n " [»] durée estimée de traitement: $ESTIMATE  "\
  || echo -n " [»] durée estimée de traitement: $ESTIMATE (début $(date +%T))  "
  time\
  for WORKAROUND in 1
  do
      for b in $INSTALLED
      do
    f_progress
    RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $b)"
      done
      f_clearline b 1 1
  done
  printf '%b\n' $RESULTF|sort -d > $CACHEDIR/sources/$a
  echo "$MACHINE $(date "+%F %T") nouvelle source $a ajoutée" >>~/.$PROGNAME/$MACHINE/history.txt
  RESULTFC=$(echo $RESULTF | wc -w)
  [ $RESULTFC -ne 0 ] && echo " [*] $RESULTFC occurrences" || echo " [×] pas d'occurrence"
  echo ; unset -v PROGRESS RESULTF
  [ $TSOURCESM = $CSOURCES ] && local TIMEFORMAT=" [»] durée totale de traitement: %lR" && unset -v DEL SOURCESNEWS TSOURCESM
    done
    echo >>~/.$PROGNAME/$MACHINE/history.txt; echo; echo; read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR
}

f_updatecache()
{
    mv -f $CACHEDIR/Installed $CACHEDIR/.old/ 2>/dev/null; printf '%b\n' $INSTALLED > $CACHEDIR/Installed
    [ -f $CACHEDIR/.old/Installed ] || return
    ICHGE=$(echo $(diff -y --suppress-common-lines $CACHEDIR/.old/Installed $CACHEDIR/Installed))
    echo $ICHGE|grep -q "<" && ICHGE=`echo $ICHGE|mawk '{gsub("<","");print $0}'`
    echo $ICHGE|grep -q ">" && ICHGE=`echo $ICHGE|mawk '{gsub(">","");print $0}'`
    echo $ICHGE|grep -q "|" && ICHGE=`echo $ICHGE|mawk '{gsub("\|","");print $0}'`
    [ -z "$ICHGE" ] && return
    echo -e "\n [>] Mise à jour du cache    \c"; f_adv &
    for i in $ICHGE
    do
  grep -qx $i $CACHEDIR/Installed && INEWS="$INEWS $i" || ISUPR="$ISUPR $i"
    done
    [ -z "$ISUPR" -a -z "$INEWS" ] && { jobs -p f_adv &>/dev/null && kill -s SIGUSR1 $(jobs -p f_adv); } && return
    [ -n "$INEWS" ] && printf '%b\n' $INEWS > $CACHEDIR/Linews; [ -n "$ISUPR" ] && printf '%b\n' $ISUPR > $CACHEDIR/Lisupr

    mv -f $CACHEDIR/sources/* $CACHEDIR/.old/sources/ 2>/dev/null
    for s in $(ls $CACHEDIR/.old/sources/)
    do
  ## supprime du cache les occurrences desinstallees
  for r in $ISUPR
  do
      grep -vx "$r" $CACHEDIR/.old/sources/$s > $CACHEDIR/sources/$s; cp -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/$s
  done
  PRERESULT=$(grep "^Package: " $SOURCESDIR$s | mawk '{print $2}')
  cp -f $CACHEDIR/.old/sources/$s $CACHEDIR/sources/$s
  ## ajoute au cache les nouvelles occurrences installees si elles apparaissent dans la source sauf si elles y sont deja
  for n in $INEWS
  do
      grep -qxm 1 "$n" $CACHEDIR/sources/$s &>/dev/null && continue
      echo "$PRERESULT"|grep -xm 1 "$n" >> $CACHEDIR/sources/$s
  done
  printf '%b\n' $(echo $(sort -d $CACHEDIR/sources/$s)) > $CACHEDIR/sources/$s
    done
    rm -f $CACHEDIR/.old/sources/* 2>/dev/null; jobs -p f_adv &>/dev/null && kill -s SIGUSR1 $(jobs -p f_adv); f_clearline r 1 35
    ## il est a noter que les paquets obsoletes (plus presents dans les sources) sont conserves dans le cache et analysables comme obsoletes
}

f_selectsources()
{
    unset -v RESUME TSOURCES
    ## formatage des sources pour la presentation, comptage des sources, presentation
    for a in $SOURCES
    do
  [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
  && SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}') $a"\
  || SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1}') $a"
  let TSOURCES++
    done
    [ -n "$ISUPR" -o -n "$INEWS" ] || echo; unset -v ISUPR INEWS
    echo " [>] $TSOURCES sources de paquets actuellement sélectionnées pour analyse:"
    echo ; unset -v TSOURCES
    printf ' [%b]\t» %b\n' $SOURCESP
    echo
    read -p " [¿] Sélectionner ou éliminer (préfixe «-») un motif pour filtrer, valider pour terminer: " MOTIF
    ## si le MOTIF est vide, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    [ "$MOTIF" = "" ] && SOURCESS=$SOURCES
    until [ "$MOTIF" = "" ]
    do
  MOTIFS="$MOTIFS $MOTIF"
  read -p " [¿] continuer la sélection des sources à analyser, valider pour terminer: " MOTIF
    done
    ## s'il n'y a que des eliminations, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    for m in $MOTIFS ; do MOTIFC="$(echo $m | cut -c 1) $MOTIFC" ; done
    MCM=$(printf '%b\n' $MOTIFC | grep -c "-") MC=$( printf '%b\n' $MOTIFC | grep -c "")
    [ "$MCM" = "$MC" ] && SOURCESS=$SOURCES
    ## boucle d'inclusion. La boucle interne permet de ne pas inclure une source deja presente (doublon)
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" != "-" ] && SELECT=$(printf '%b\n' $SOURCES | grep $MOTIF) || continue
  for s in $SELECT
  do
      [[ $(printf '%b\n' "$SOURCESS" | grep -w "$s") ]] && continue
      SOURCESS="$SOURCESS $s"
  done
    done
    ## boucle d'exclusion
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" = "-" ] && MOTIF=$(echo $MOTIF | cut -c 2-) && SOURCESS=$(printf '%b\n' $SOURCESS | grep -v $MOTIF)
    done
    SOURCES=$SOURCESS
    echo
    ## exclusion des fichiers qui ne sont pas des descripteurs de paquets
    echo " [>] Analyse des sources:"
    [ "$SOURCES" != "" ] && NSOURCES=$(printf '%b\n' $SOURCES | grep -c "") || NSOURCES=0
    for a in $SOURCES
    do
  if ! grep -qm 1 "^Package: " $SOURCESDIR$a
  then
      [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
      && b=$(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}')\
      || b=$(ls -sh $SOURCESDIR$a | mawk '{print $1}')
      echo " [×] non pertinente: $a [$b]"
      continue
  fi
  SOURCESC="$SOURCESC $a" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v MOTIFC MOTIFS SOURCESC SOURCESP SOURCESS
    [ "$SOURCES" = "" ] && TSOURCES=0
    [ "$TSOURCES" != "0" ]\
    && SOURCES=$(printf '%b\n' $SOURCES|sort -d) SOURCES=$(echo $SOURCES)\
    && echo " [»] $TSOURCES sources sur $NSOURCES à traiter dans la sélection:" && printf ' [*] [%b]\n' $SOURCES\
    || echo " [»] pas de sources à traiter dans la sélection"
    echo
    while true; do let COUNT++; echo ${FUNCNAME[$COUNT]}|grep -qx main && MAIN=$COUNT && unset -v COUNT && break; done
    RESUME=* ; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    while true
    do
  case "$RESUME" in
      q|Q) f_exit; RESUME=*;;
      h)  less $0; RESUME=*;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break $MAIN; };;
      p)  [ "$TSOURCES" != "0" ] && $CLEAR && f_selectsources || RESUME=r;;
      l|L|"") [ "$TSOURCES" != "0" ] && break || [ "$RESUME" = "" ] && RESUME=r || RESUME=*;;
      r|R) $CLEAR; f_init; f_selectsources;;
      *)  [ "$TSOURCES" != "0" ]\
    && read -s -n 1 -p " [¿] Préciser encore la sélection - Recommencer - Lancer l'analyse <p/r/L>: " RESUME\
    && f_clearline r 1 104
    [ "$TSOURCES" = "0" ] && read -s -n 1 -p " [¿] Recommencer <R>: " RESUME && f_clearline r 1 50;;
  esac
    done
}

f_occm()
{
    while true
    do
  read -s -n 1 -p " [¿] Par la suite traiter aussi les sources sans occurrences ? <o/N>: " SELECT
  f_clearline r 1 75
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break 2; };;
      o|O)  OCCLESS=0 ; unset -v SELECT ; $CLEAR ; break;;
      n|N|"") OCCLESS=1 ; unset -v SELECT ; $CLEAR ; break;;
  esac
    done
}

f_squeezecache()
{
    echo
    for s in $SOURCES
    do
  local CSOURCES CSOURCESM CSOURCESS ; let CSOURCES++ ; let CSOURCESS++
  RESULTF=$(cat $CACHEDIR/sources/$s) RESULTFC=$(echo $RESULTF | wc -w)
  ## eval interprete l'item suivant dans la liste comme une commande s'il y a un espace
  RESULTF=`echo $RESULTF|mawk '{gsub(" ","¿");print $0}'`
  ## attribution d'une variable dynamique au resultat individuel - utilisation de eval
  ## identification par le n° de traitement $CSOURCES, attribution du contenu de RESULTF a la nouvelle variable
  ## la nouvelle variable recoit le nom de la source en alias, permet la concordance n°/nom
  [ $RESULTFC -ne 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [*] $RESULTFC occurrences\t$s"
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [×] pas d'occurrence\t$s" && let CSOURCESM++
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 1 ] && let CSOURCES-- && echo -e " [×] pas d'occurrence\t$s"
  unset -v RESULTF
    done
    echo ; TSOURCES=$CSOURCES ; [ -z $CSOURCESM ] && CSOURCESM=0
    echo " [»] $(($CSOURCES - $CSOURCESM)) sources sur $CSOURCESS présentent des occurrences de paquets installés sur $MACHINE"
    echo ; unset -v CSOURCESM CSOURCESS CSOURCES
    ## concatenation des resultats individuels - utilisation de la substitution de variable {!RESULTF}
    for (( n=1; n <= TSOURCES; n++ ))
    do
  RESULTF=RESULTF$n ## RESULTF se substitue a la variable dynamique dont le contenu est appele par {!RESULTF}
  RESULTFP=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTFP=$(echo $RESULTFP)
  RESULTFT="$RESULTFT $RESULTFP" ## concatenation, doublons compris elimines par sort -u par la suite
  SOURCESN="$SOURCESN $n" ## extrait les numeros des sources disponibles de 1 a n sources
    done
    SOURCESN=$(echo $SOURCESN) SOURCESNP=`echo $SOURCESN|mawk '{gsub(" ","\&|");print $0}'`
    RESULTFTS=$(printf '%b\n' $RESULTFT | sort -d) RESULTFTU=$(echo $(printf '%b\n' $RESULTFT | sort -u))
    RESULTFTC=$(echo $RESULTFT|wc -w) RESULTFTUC=$(echo $RESULTFTU|wc -w) RESULTFTCC=$(($RESULTFTC-$RESULTFTUC))
    UNKNOWNS=$(printf '%b\n' $INSTALLED $RESULTFTU|sort -d|uniq -u) UNKNOWNC=$(echo $UNKNOWNS|wc -w)
    NOPURGE=`dpkg --admindir=$INSTALLDIR -l|grep "^rc "|mawk '{print $2}'` NOPURGEC=$(echo $NOPURGE|wc -w)
    LINEWSC=$(cat $CACHEDIR/Linews 2>/dev/null|wc -w); LISUPRC=$(cat $CACHEDIR/Lisupr 2>/dev/null|wc -w)
    LINEWS=$(printf ' [%b]' $(cat $CACHEDIR/Linews 2>/dev/null)) LISUPR=$(printf ' [%b]' $(cat $CACHEDIR/Lisupr 2>/dev/null))
    echo
    echo " [*] paquets installés sur $MACHINE: $NINSTALLED"
    echo " [*] occurrences installées sur $MACHINE: $RESULTFTUC"
    echo " [*] paquets installés non analysés: $(($NINSTALLED-$RESULTFTUC))"
    echo " [*] croisements d'occurrences: $RESULTFTCC"
    echo " [*] occurrences totales: $RESULTFTC"
    echo
}

f_postproc()
{
    f_fmt() { fmt -w $(tput cols); }
    f_tee() { [ $RECORD = 1 ] && tee -a $RECFILE || tee; }
    f_less() { [ $LESS = 1 ] && less -m~ || tee; }
    f_pager()
    {
  read -s -n 1 -p " [¿] afficher les occurrences avec Less - directement - ne pas afficher <L/d/n>: " PAGER
  f_clearline r 1 80 ; [ "$PAGER" = "d" -o "$PAGER" = "n" ] || PAGER=L ; PAGERM="\c"
  [ "$PAGER" = L ] && LESS=1 PAGERM="      [affichage dans le pager]" || LESS=0; [ "$PAGER" = n ] && PAGERM="      -------------------------"
    }

    f_dores()
    {
  for S in $S
  do
      RESULTF=RESULTF$S RESULTFALIAS=$(eval alias RESULTF$S | cut -d "'" -f2) ; [ "$1" = "-a" ] && return
      RESULTF=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTF=$(echo $RESULTF)
      RESULTFC=$(echo $RESULTF|wc -w) ; [ "$1" = "-r" ] && return
      OBSOLETES=OBSOLETES$S; OBSOLETES=`echo ${!OBSOLETES}|mawk '{gsub("¿"," ");print $0}'`
      OBSOLETES=$(echo $OBSOLETES); OBSOLETESC=$(echo $OBSOLETES|wc -w)
  done
    }
    f_obs()
    {
  [ -n "$OBSOLETESTC" ] && return
  echo -n " [»] traitement    "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for S in $SOURCESN
  do
      f_dores -r; unset -v OBSOLETES
      for p in $RESULTF
      do
    grep -qxm 1 "Package: $p" $SOURCESDIR$RESULTFALIAS\
    || OBSOLETES="$OBSOLETES¿$p" OBSOLETEST="$OBSOLETEST $p"
      done
      eval OBSOLETES$S="$OBSOLETES"
  done
  OBSOLETEST=$(printf '%b\n' $OBSOLETEST|sort -u) OBSOLETESTC=$(echo $OBSOLETEST|wc -w)
  for o in $OBSOLETEST
  do
      unset -v COUNTER NOBS
      for S in $SOURCESN
      do
    f_dores -r
    let COUNTER++; [ $COUNTER -eq 1 ]\
    && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
    && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
    && OBSOLETESTR="$OBSOLETESTR $o"
    LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS); [ -z "$LOC" ] && continue
    LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
    VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
    [ "$VERI" = "$VER" ] && NOBS=1
      done
      [ -n "$NOBS" ] && OBSOLETESTR=$(printf '%b\n' $OBSOLETESTR|grep -vx $o)
  done
  OBSOLETESTRC=$(echo $OBSOLETESTR|wc -w); unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }
    f_twin()
    {
  [ -n "$TWIN" -o -n "$SINGLE" ] && return
  echo -n " [»] traitement    "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for u in $RESULTFTU
  do
      unset -v COUNTER
      for s in $RESULTFTS
      do
    [[ "$u" != "$s" ]] && continue
    let COUNTER++
      done
      [[ "$COUNTER" < 2 ]] && SINGLE="$SINGLE $u" && continue
      TWIN="$TWIN $u"
      TWINP="$TWINP $COUNTER"¿"$u"
  done
  TWINC=$(echo $TWIN|wc -w) SINGLEC=$(echo $SINGLE|wc -w)
  TWINP=`printf ' %b\n' $TWINP|sort -d|mawk '{gsub("¿","×  ");print $0}'`
  SINGLEP=$(printf ' [%b]' $SINGLE) ; TWIND=$(printf '%b\n' $TWIN)
  unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }

    f_displayg()
    {
  { echo; echo " [>] [$MACHINE] Occurrences globales:"; }|f_tee
  [ "$SOURCESG" = "" ] &&\
  for S in $SOURCESN;do f_dores -r;[ $RESULTFC -ne 0 ] && SOURCESG="$SOURCESG $RESULTFALIAS" && SOURCESNG="$SOURCESNG $S" && let SOURCESGC++
  done
  [ "$SOURCESG" = "" ] && { echo " [×] Aucune des sources analysées n'a d'occurrence installée sur $MACHINE"; echo -e "\n\n"; }|f_tee && return
  { echo " [»] $SOURCESGC sources analysées ont des occurrences installées sur $MACHINE:"; echo; }|f_tee
  for S in $SOURCESNG; do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"|f_tee; TTLOCC=$(($TTLOCC+$RESULTFC)); done
  f_obs
  NOSOURCEDC=$(($OBSOLETESTRC+$UNKNOWNC)) SOURCEDC=$(($RESULTFTUC-$OBSOLETESTRC))
  { echo " [*] total: $TTLOCC occurrences"; echo; echo " [*] $NINSTALLED paquets installés sur $MACHINE"
  echo " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées"
  echo " [*] dont $OBSOLETESTRC paquets obsolètes et $UNKNOWNC paquets d'origine inconnue"
  echo " [*] $SOURCEDC paquets installés présents dans les sources analysées:"; echo; }|f_tee ; unset -v TTLOCC
  f_pager
  [ "$SOURCEDP" = "" ] && SOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $RESULTFTU|sort -d|uniq -u))
  [ "$NOSOURCEDP" = "" ] && NOSOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $UNKNOWNS|sort -d))
  [ "$NOPURGEP" = "" ] && NOPURGEP=$(printf ' [%b]' $NOPURGE)
  [ $PAGER = L ] && { printf '\n%b\n' " [*] $SOURCEDC paquets installés présents dans les sources analysées:" "$SOURCEDP"|f_fmt
  [ $NOSOURCEDC -gt 0 ] && printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $LINEWSC -gt 0 ] && printf '\n%b\n' \
  " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt
  [ $LISUPRC -gt 0 ] && printf '\n%b\n' \
  " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; }|f_tee |f_less
  [ $PAGER = d ] && { echo "$SOURCEDP"|f_fmt; [ $NOSOURCEDC -gt 0 ] &&\
  printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $LINEWSC -gt 0 ] && printf '\n%b\n' \
  " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt
  [ $LISUPRC -gt 0 ] && printf '\n%b\n' \
  " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; } |f_tee
  [ $PAGER = n ] && echo -e "$PAGERM"|f_tee || echo -e "$PAGERM"; { echo ; echo; }|f_tee
  [ $TSOURCES -eq 1 ] && { [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo; } && return

  f_twin
  [ $TWINC -eq 0 ] && { echo " [×] aucun croisement d'occurrence de paquets installés sur $MACHINE entre les sources analysées"
  echo -e "\n\n"; }|f_tee && return
  { echo " [*] $SINGLEC occurrences uniques";echo " [*] $RESULTFTCC croisements d'occurrences";echo " [*] $TWINC occurrences croisées:"; }|f_tee
  f_pager
  [ $PAGER = L ] && { printf '\n%b\n%b\n\n%b' " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:" "$TWINP"
  printf '\n\n\n%b\n\n%b' " [*] $SINGLEC occurrences uniques:" "$SINGLEP"|f_fmt; }|f_tee |f_less && echo -e "\n$PAGERM"
  [ $PAGER = d ] && { echo -e "\n$TWINP";echo -e "\n";echo -e " [*] $SINGLEC occurrences uniques:\n";echo "$SINGLEP"|f_fmt; }|f_tee
  [ $PAGER = n ] && echo -e "\n$PAGERM"|f_tee
  [ $RECORD = 1 ] && echo -e "\n\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    f_display()
    {
  { echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo; }|f_tee
  { for (( S=1; S <= $TSOURCES; S++ )); do f_dores -r; echo $SELECTS|grep -w $S &>/dev/null
  [ $? -eq 0 ] && echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]" || echo " [×]";done; }|f_tee
  f_pager
  [ $PAGER != n  ] && f_obs &&\
  for S in $SELECTS
  do
      f_dores
      echo -e "\n [*] $RESULTFC occurrences installées présentes dans le cache de la source [$RESULTFALIAS]:"
      [ $RESULTFC -ne 0 ] && echo && printf ' [%b]' $RESULTF|f_fmt; echo
      [ $OBSOLETESC -ne 0 ] && echo " [*] dont $OBSOLETESC occurrences obsolètes:" && printf ' [%b]' $OBSOLETES|f_fmt && echo
  done |f_tee|f_less ; echo|f_tee
  [ $PAGER = n ] && echo -e "$PAGERM\n"|f_tee || echo -e "$PAGERM\n"; echo|f_tee
  { printf " [»] occurrences uniques et croisées des sources"; printf ' [%b]' $SELECTS; echo ":"; }|f_tee
  f_pager
  f_sort()
  {
      f_twin
      for S in $SELECTS
      do
    f_dores -r
    for r in $RESULTF
    do
        echo "$TWIND"|grep -qxm 1 "$r" &>/dev/null && MULTIX="$MULTIX $r" && continue
        UNIX="$UNIX $r"
    done
    UNIXC=$(echo $UNIX|wc -w) MULTIXC=$(echo $MULTIX|wc -w)
    echo -e "\n [$S] $RESULTFALIAS [$(($UNIXC+$MULTIXC)) occurrences]" ; echo
    [ $UNIXC -ne 0 ] && echo " [*] $UNIXC occurrences uniques:" && printf ' [%b]' $UNIX|f_fmt && echo
    [ $MULTIXC -ne 0 ] && echo " [*] $MULTIXC occurrences croisées:" && printf ' [%b]' $MULTIX|f_fmt && echo
    unset -v UNIX MULTIX
      done |f_tee |f_less ; echo -e "\n$PAGERM\n\n"
      [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo
  }
  [ $PAGER != n  ] && f_sort || echo -e "\n$PAGERM\n\n\n"|f_tee
    }
    f_displaym()
    {
  echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo
  for ((S=1;S<=TSOURCES;S++)); do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"; done; echo
  while true
  do
      read -p " [¿] afficher les occurrences pour $SOURCESNP (défaut &) <$SOURCESN>: " SELECTS
      case "$SELECTS" in
    q|Q) f_exit;;
    h)  less $0;;
    "") SELECTS=$SOURCESN ; $CLEAR ; f_display ; break;;
    *)  SELECTS=$(printf '%b\n' $SELECTS|sort -u) doit=1
        for s in $SELECTS; do echo $SOURCESN|grep -w $s &>/dev/null; [ $? -ne 0 ] && doit=0; done
        [ $doit -ne 0 ] && $CLEAR && f_display && break;;
      esac
  done
    }

    f_package()
    {
  { echo -e "\n [>] [$MACHINE] Analyse par paquets:\n"; echo " [»] analyse des occurrences croisées entre les sources analysées:"; }|f_tee
  f_twin
  f_x()
  {
      { echo " [*] $RESULTFTCC croisements d'occurrences"
      echo " [*] $TWINC occurrences croisées:"; echo; }|f_tee
      f_pager
      [ $PAGER = n  ] && echo -e "$PAGERM\n"|f_tee && return
      for x in $TWIN
      do
    [ -z "$COUNT" -a $PAGER = L ] && printf '%b\n%b\n\n'\
    " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:"
    let COUNT++; echo " [$COUNT] [$x]"; unset -v COUNTER
    for S in $SOURCESN
    do
        f_dores -r; let COUNTER++
        [ $COUNTER -eq 1 ]\
        && LOCI=$(grep -xnm 1 "Package: $x" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo -e " $VERI $STATI"\
        && for d in $(ls $CACHEDIR/.old/sources/.deleted/)
        do grep -qxm 1 "$x" $CACHEDIR/.old/sources/.deleted/$d && echo " présent dans la source supprimée $d"; done
        LOC=$(grep -xnm 1 "Package: $x" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $x && echo " obsolète dans $RESULTFALIAS"; true; } && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS"
    done
    echo
      done |f_tee |f_less ; unset -v COUNT COUNTER; echo -e "$PAGERM\n"
  }
  [ $TWINC -eq 0 ]&&echo -e " [×] aucun croisement d'occurrences de paquets installés sur $MACHINE entre les sources analysées\n"|f_tee||f_x

  echo -e "\n\n [»] analyse des paquets installés non présents dans les sources analysées:"|f_tee
  f_u()
  {
      echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { COUNT=0 TUNKNOWNS=$UNKNOWNS; [ $PAGER = L ] && echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"
      for u in $UNKNOWNS
      do
    unset -v COUNTER
    for d in $(ls $CACHEDIR/.old/sources/.deleted/)
    do
        grep -qxm 1 "$u" $CACHEDIR/.old/sources/.deleted/$d && { TUNKNOWNS=$(printf '%b\n' $TUNKNOWNS|grep -vx $u); let COUNTER++
        [ $COUNTER -eq 1 ] && { let COUNT++; echo -e "\n [$COUNT] [$u]"; }; echo " origine possible: source supprimée [$d]"; }
    done
   
      done
      [ $COUNT -gt 0 -a $COUNT -lt $UNKNOWNC ] && { echo -e \
      "\n [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $(($UNKNOWNC-$COUNT)) autres paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }\
      || { [ $COUNT -eq 0 ]&&echo " [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $UNKNOWNC paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }; }|f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $UNKNOWNC -eq 0 ] && echo -e " [×] aucun paquet d'origine inconnue installé sur $MACHINE\n"|f_tee || f_u

  echo -e "\n\n [»] analyse des occurrences obsolètes dans le cache des sources analysées:"|f_tee
  f_obs
  f_o()
  {
      echo " [*] $OBSOLETESTC occurrences obsolètes:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { OBS=$OBSOLETESTC; echo; [ $PAGER = L  ] && { echo " [*] $OBSOLETESTC occurrences obsolètes:"; echo; }
      for o in $OBSOLETEST
      do
    let COUNT++; unset -v COUNTER NOBS
    for S in $SOURCESN
    do
        f_dores -r
        let COUNTER++; [ $COUNTER -eq 1 ] && echo " [$COUNT] [$o]"\
        && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo " $VERI $STATI" && OBSR="$OBSR $o"
        LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $o && echo " obsolète dans $RESULTFALIAS"; true; }\
        && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS" ; [ "$VERI" = "$VER" ] && NOBS=1
    done
    [ -n "$NOBS" ] && { echo " [¡] la version installée de $o n'est PAS obsolète"; let OBS--; OBSR=$(printf '%b\n' $OBSR|grep -vx $o); }
    echo
      done
      [ $OBS -eq 0 ] && echo " [×] aucun des paquets installés sur $MACHINE n'est obsolète"\
      || { echo -e "\n [*] $OBS paquets installés sur $MACHINE sont obsolètes:"; printf ' [%b]' $OBSR|f_fmt; echo; }
      [ $UNKNOWNC -ne 0 ]\
      && echo " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes"
      } |f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $OBSOLETESTC -eq 0 ] && { echo " [×] aucune occurrence obsolète de paquets installés sur $MACHINE dans les sources analysées"
  [ $UNKNOWNC -ne 0 ] &&\
  echo -e " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes\n\n"; } |f_tee || f_o
  [ $RECORD = 1 ] && echo -e "\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    echo
    [ $TSOURCES -eq 0 -a $OCCLESS -eq 1 ]\
    && echo " [>] Aucune des sources traitées ne présente d'occurrence en concordance avec les paquets installés sur $MACHINE"\
    && echo " [»] aucune analyse à effectuer" && echo && read -s -n 1 -p " [-] valider pour continuer... " && f_clearline r 1 35 && return 2
    echo " __________________________________________________________________________"
    echo " [-] Enregistrer la prochaine séquence - Aide - Accueil - Quitter <r/h/w/q>" ; RECORD=0 REC=""
    while true
    do
  read -s -n 1 -p " [¿]$REC [$MACHINE]: Analyse globale - Par sources - Par paquets <g/s/p>: " SELECT
  f_clearline r 1 110
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; return; };;
      r) REC=" [R]" RECORD=1;echo -e "\n\n $(date)" >>$RECFILE;;
      g) $CLEAR; f_displayg;break;;
      s) $CLEAR; f_displaym;break;;
      p) $CLEAR; f_package;break;;
  esac
    done
    f_postproc
}

f_home()
{
    [ -d ~/.$PROGNAME/$(uname -n) ] || { $CLEAR; echo -e "\n [>] Initialisation de $PROGNAME\n"; MACHINE=$(uname -n)
    f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }
    [ -d ~/.$PROGNAME/_alternate ] || { mkdir -p ~/.$PROGNAME/_alternate/
    echo "Copiez ici les répertoires /var/lib/apt/lists/ et /var/lib/dpkg/ d'un système alternatif que vous souhaitez analyser"\
    > ~/.$PROGNAME/_alternate/readme.txt; }

    $CLEAR; echo -e "\n\n\n\n\n\n"
    for w in Advanced  Packaging Tool DIAGnostic
    do
  NL=$(echo ${#w}) NLA=$NL; echo -n " "
  for ((l=1;l<=NL;l++))
  do
      L=$(echo $w|cut -c $l); echo $L|grep -q [A-Z] && L="\033[1m$L\033[0m"
      for ((la=NLA;la>=0;la--))
      do
    for ((s=la;s>=1;s--)); do SPACE="$SPACE "; done
    echo -ne "$SPACE$L "; NSPACE=$(echo ${#SPACE})
    unset -v SPACE; sleep 0.01; [ $NSPACE -eq 0 ] && break
    for ((b=1;b<=NSPACE+2;b++)); do echo -ne "\b"; done
      done
      NLA=$(($NLA-1))
      let INTER++; for ((s=2;s<=INTER/2;s++)); do echo -n " "; done
  done
  echo; unset -v INTER
    done
    echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n [>] $PROGNAME"; echo

    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ] && { echo " [»] un système alternatif a été détecté"
    [ -w ~/.$PROGNAME/_alternate/lists/ -a -w ~/.$PROGNAME/_alternate/dpkg/ ]\
    || { echo -e "\a\n [!] la configuration alternative n'a pas les droits en écriture, sortie\n"; exit 1; }
    [[ $(ADM=~; dpkg --admindir=$ADM/.$PROGNAME/_alternate/dpkg/ -l 2>/dev/null) ]]\
    || { echo -e "\a\n [!] le répertoire ~/.$PROGNAME/_alternate/dpkg/ n'est pas une configuration valide pour dpkg, sortie\n"; exit 1; }
    read -p " [¿] nom du système: " MACHINE; f_clearline r 1 100
    MACHINE=$(echo $MACHINE|tr -d ".%$&|<>*\'\"# /\\" 2>/dev/null|tr "[A-Z]" "[a-z]"|sed 's/^-//')
    [ $(echo ${#MACHINE}) -gt 35 ] && echo " [!] $MACHINE: ce nom est déraisonnablement long..." && sleep 3 && f_clearline r 1 120 && return
    [ -d ~/.$PROGNAME/$MACHINE ] && echo " [!] $MACHINE: ce nom de système est déjà utilisé..." && sleep 3 && f_clearline r 1 100 && return
    read -s -n 1 -p " [¿] ce nom est-il correct: $MACHINE ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 100 && return
    $CLEAR; echo -e "\n [>] Initialisation du cache pour $MACHINE\n"; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }

    echo " [»] systèmes analysables:"
    echo " [1] $(uname -n)"; COUNTER=1 MACHINES=1 MACHINESP=1; unset -v MACHINESUP MACHINESUPP
    for m in $(ls ~/.$PROGNAME/)
    do
  [ "$m" = "$(uname -n)" -o "$m" = "_alternate" ] && continue; [ -d ~/.$PROGNAME/$m ] || continue
  let COUNTER++; alias $COUNTER=$m; MACHINES="$MACHINES $COUNTER" MACHINESP="$MACHINESP/$COUNTER"
  MACHINESUP="$MACHINESUP $COUNTER" MACHINESUPP="$MACHINESUPP/$COUNTER"; echo " [$COUNTER] $m"
    done
    echo; unset -v COUNTER; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    [ -n "$MACHINESUP" ] && MACHINESUPP=$(echo $MACHINESUPP|sed 's/^\///') &&\
    while true
    do
  read -s -n 1 -p " [¿] Sélectionner un système - Supprimer un système (défaut 1) <$MACHINESP/->: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      -)  read -s -n 1 -p " [¿] sélectionner un système pour SUPPRESSION <$MACHINESUPP>: " SELECTM; f_clearline r 1 100
    echo $MACHINESUP|grep -w $SELECTM &>/dev/null\
    && { read -s -n 1 -p " [¿] supprimer $(alias $SELECTM|cut -d "'" -f2) de $PROGNAME ? <o/N>: " DEL; f_clearline r 1 100
    [ "$DEL" = o ] && rm -fr ~/.$PROGNAME/$(alias $SELECTM|cut -d "'" -f2); unset -v DEL; return; };;
      ""|1) MACHINE=$(uname -n); break;;
      *)  echo $MACHINES|grep -w $SELECT &>/dev/null && MACHINE=$(alias $SELECT|cut -d "'" -f2) && break;;
  esac
    done || MACHINE=$(uname -n); for m in $MACHINESUP; do unalias $m &>/dev/null; done
    while true
    do
  read -s -n 1 -p " [¿] [$MACHINE]: travailler sur l'ensemble des sources ? <O/n>: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      o|O|"") $CLEAR; echo; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; OCCLESS=1; f_squeezecache; f_postproc; break;;
      n) $CLEAR; echo; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; f_selectsources; f_occm; f_squeezecache; f_postproc; break;;
  esac
    done
}

while true; do f_home; done

Hors ligne

#19 22-06-2009 08:04:22

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Bonjour nofun,
J'ai tout fait ça :

- coller le texte complet du script dans un éditeur (Gedit, Kate, KEdit ou NEdit par exemple) et enregistrer sous le nom apt-diag
- donner les droits en exécution au script (chmod +x ./apt-diag)

Pas ça :
- on peut lancer le script en donnant son chemin complet: /home/user/apt-diag par exemple ou en se mettant dans son répertoire et en l'appelant directement: ./apt-diag
- on peut placer le script dans /usr/local/bin/ pour pouvoir l'appeler directement (/usr/local/bin/ est dans le path). Dans ce cas, penser à changer le propriétaire à root (chown root:root ./apt-diag)


Et c'est parfait ! wink
Merci nofun, je te présente mes excuses pour le retard à la coopération, la vie... les filles... voire plus...

Amitié, Joel


"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#20 23-06-2009 17:10:43

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

smolski a écrit :

je te présente mes excuses pour le retard à la coopération, la vie... les filles... voire plus...


alors tu es tout excusé ;)

Bon, version 0.2b, encore une correction dans f_updatecache mais qui n'oblige pas à repartir sur un cache tout neuf:

#!/bin/bash

############                                                          ##########
# apt-diag #                                                          # v.0.2b #
################################################################################
# author: (C)2009 nofun_AT_laposte_DOT_net ## bug report, suggestion, wishlist #
####################################################### are welcome ############
# GNU General Public License v.3 or later http://www.gnu.org/copyleft/gpl.html #
################################################################################
######## homepage: http://debian-facile.org/forum/viewtopic.php?id=1285 ########
################################################################################

# Changelog:

# v.0.1 (avril 2009):
# version initiale.

# v.0.2 (mai 2009):
# correction d'un bug dans la mise a jour du cache (f_updatecache): le cache mis
# a jour avec la version precedente (0.1) a une forte probabilite de corruption.
# fonctionnalite: ajout de la presentation des derniers paquets ajoutes et
# supprimes depuis la derniere mise a jour du cache.

# v.0.2a (mai 2009):
# correction d'un bug dans la mise a jour du cache (f_updatecache): le cache mis
# a jour avec la version precedente (0.2) a une probabilite de corruption.

# v.0.2b (juin 2009):
# correction d'un bug dans la mise a jour du cache (f_updatecache): les paquets
# deja installes mais nouveaux dans une source sont maintenant ajoutes au cache
# de cette source. Cette version corrige correctement le cache mis a jour avec
# la version precedente (0.2a).

################################################################################

# apt-diag: pour que claires les sources demeurent

# apt-diag cherche a donner une vue d'ensemble des paquets installes sur un
# systeme utilisant apt (Advanced Packaging Tool du projet Debian).
# Il aide en particulier a determiner de quelle source peut provenir un paquet,
# indique quand c'est le cas la presence d'un meme paquet dans de multiples
# sources et dresse la liste des paquets n'appartenant plus a aucune source
# (ensemble des paquets obsoletes et des paquets de source inconnue).
# C'est un bon complement a 'apt-cache policy nom_du_paquet'.

# De plus, apt-diag maintient un cache personnel des paquets par source, ce qui
# lui permet d'etablir la liste des paquets obsoletes en provenance de chaque
# source, information sinon indisponible. Les sources supprimees sont egalement
# archivees. Le degre d'information que fournit apt-diag est donc dependant de
# la date d'initialisation du cache.

# apt-diag n'agit pas sur le systeme de gestion des paquets, il est donc su^r
# pour le systeme hote. Le seul appel au systeme de gestion des paquets est du
# type 'dpkg -l' ou 'dpkg --get-selections'. De ce fait, apt-diag peut analyser
# un systeme autre que le systeme hote si on lui fournit les repertoires
# /var/lib/apt/lists/ et /var/lib/dpkg/ d'un syteme alternatif (a copier dans
# ~/.apt-diag/_alternate) et fonctionne parfaitement en simple utilisateur.
# apt-diag possede une fonctionnalite d'enregistrement des analyses dans un
# fichier, ce qui permet de conserver une trace ou de communiquer l'etat du
# systeme a un tiers.

# Limitations:
# tout diagnostic est faillible et sujet a des erreurs d'interpretation. Il
# appartient a l'administrateur d'evaluer les informations fournies par apt-diag
# en particulier en confrontant les resultats obtenus avec ceux que pourront lui
# procurer les outils systeme a sa disposition. La licence GNU GPL sous laquelle
# apt-diag est delivre n'offre aucune garantie de bon fonctionnement.
# apt-diag n'a pas (encore) ete teste en presence de downgrade ou d'apt-pinning
# et plus generalement demande a etre teste davantage.
# apt-diag n'est pas integre au systeme de gestion des paquets, de ce fait la
# mise a jour du cache n'est pas automatique lors de la mise a jour du systeme.
# apt-diag evalue les paquets par leur nom, l'evaluation par numero de version
# est embryonnaire et demanderait d'autres techniques de programmation.
# Si un paquet a ete installe depuis une source par la suite supprimee et que ce
# paquet apparait toujours dans une autre source avec une version inferieure,
# rien de particulier n'est signale au sujet de ce paquet par apt-diag.

# Merci de distribuer apt-diag avec le texte ci-dessus.
# Bonne utilisation.

################################################################################
PROGNAME=$(basename $0)

f_conv()
{
    #TestCharSet: aéèêîïà¿»×x
    grep -m 1 "TestCharSet:" $0 > /tmp/testcharset
    PRGCHARSET=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'|tr [a-z] [A-Z]`
    SYSCHARSET=$(locale charmap)
    ! echo $SYSCHARSET|grep -q $PRGCHARSET && echo -e "\n [>] Conversion de $PROGNAME de $PRGCHARSET vers $SYSCHARSET...\c"\
    && { iconv -f "$PRGCHARSET" -t "$SYSCHARSET"//TRANSLIT $0 -o /tmp/$PROGNAME && chmod +x /tmp/$PROGNAME\
    && grep -m 1 "TestCharSet:" /tmp/$PROGNAME > /tmp/testcharset && PRGCHARSETR=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'`\
    && { [ "$PRGCHARSET" = "$(echo $PRGCHARSETR|tr [a-z] [A-Z])" ] && echo " ok" || echo; } && rm -f /tmp/testcharset\
    && echo -e " [*] la version $PRGCHARSETR de $PROGNAME est disponible dans /tmp/$PROGNAME\n" && exit\
    || { echo -e "\a\n [!] un probleme est survenu pendant la conversion, sortie\n"; exit 1; }; }
}
[ -d ~/.$PROGNAME ] || { f_conv; [ -d /var/lib/apt/lists/ ] && [[ $(dpkg -l 2>/dev/null) ]]\
|| { echo -e "\a\n [!] $PROGNAME n'est pas compatible avec le système hôte, sortie\n"; exit 1; }; }

which bc &>/dev/null|| { echo -e "\a\n [>] $PROGNAME\n [!] Ce script nécessite bc pour fonctionner, veuillez l'installer:\n"
aptitude show bc; echo -e "\n [*] aptitude -(s)v install bc\n"; exit 1; }

[ "$1" = "-c" ] && ECHO=echo || CLEAR=clear ; hash grep mawk
grep -q "Ratio $(uname -n):" ~/.$PROGNAME/ratio 2&>/dev/null && RATIO=`grep "Ratio $(uname -n):" ~/.$PROGNAME/ratio|cut -d " " -f3`
################################################################################

f_clearline()
{
    [[ $1 = [br] ]] && [ -n "$3" ] && echo $2$3|grep -qx [0-9]* || return 1
    while true
    do
  local COUNTER; let COUNTER++ ; echo -ne "\\$1"
  [ $COUNTER = $2 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; echo -ne " "
  [ $COUNTER = $3 ] && unset -v COUNTER && break
    done
    while true
    do
  let COUNTER++ ; [ $1 = r ] && COUNTER=$3
  echo -ne "\\$1" ; [ $COUNTER = $3 ] && return
    done
}

f_exit() { read -s -n 1 -p " [¿] Quitter $PROGNAME ? <O/n>: " EXIT; [ "$EXIT" = n ] && f_clearline r 1 45 && return; echo; echo; exit; }

f_init()
{
    for (( s=1; s <= TSOURCES; s++ )); do unset -v RESULTF$s OBSOLETES$s; done
    unset -v DEL INEWS ISUPR NOPURGEP NOSOURCEDP OBSOLETES OBSOLETEST OBSOLETESTC OBSOLETESTR
    unset -v RESULTF RESULTFT SINGLE SOURCEDP SOURCESG SOURCESGC SOURCESN SOURCESNG TSOURCES TWIN TWINP
    echo
    CACHEDIR=~/.$PROGNAME/$MACHINE/cache ; RECFILE=~/$PROGNAME\_$MACHINE\-$(date +%Y%m%d-%H%M%S).txt
    [ -d $CACHEDIR ] || {  mkdir -p $CACHEDIR/.old/sources/.deleted/ $CACHEDIR/sources/
    echo "$MACHINE $(date "+%F %T") initialisation du cache" >> ~/.$PROGNAME/$MACHINE/history.txt; }
    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ]\
    && mv -f ~/.$PROGNAME/_alternate/lists/ ~/.$PROGNAME/_alternate/dpkg/ ~/.$PROGNAME/$MACHINE/
    [ "$MACHINE" = "$(uname -n)" ] && SOURCESDIR=/var/lib/apt/lists/ INSTALLDIR=/var/lib/dpkg/\
    || SOURCESDIR=~/.$PROGNAME/$MACHINE/lists/ INSTALLDIR=~/.$PROGNAME/$MACHINE/dpkg/

    ## extraction de la liste des paquets installes sur le systeme
    INSTALLED=$(dpkg --admindir=$INSTALLDIR --get-selections |grep -w "install$" |mawk '{print $1}' |sort -d)
    NINSTALLED=$(echo $INSTALLED | wc -w)
    ## extraction et nettoyage des sources
    SOURCES=$(ls $SOURCESDIR |grep -vx lock |grep -vx partial)
    for a in _source_Sources i18n_Translation .ed$
    do
  SOURCES=$(printf '%b\n' $SOURCES | grep -v $a)
    done
    for s in $SOURCES
    do
  grep -qm 1 "^Package: " $SOURCESDIR$s || continue
  SOURCESC="$SOURCESC $s" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v SOURCESC
    echo " [»] Paquets installés: $INSTALLDIR Paquets disponibles: $SOURCESDIR"
    echo " [»] $NINSTALLED paquets installés sur $MACHINE"; echo
}

f_progress()
{
    let PROGRESS++
    [ $PROGRESS = $ALPHAPROGRESS ] && echo -ne "\b-" && return
    [ $PROGRESS = $ALPHAPROGRESS2 ] && echo -ne "\b\\" && return
    [ $PROGRESS = $ALPHAPROGRESS3 ] && echo -ne "\b|" && return
    [ $PROGRESS = $ALPHAPROGRESS4 ] && echo -ne "\b/" && PROGRESS=0
}
f_adv()
{
    trap 'break' SIGUSR1
    while true
    do
  echo -ne "\b\b\b\b.   "; sleep .5; echo -ne "\b\b\b\b..  "; sleep .5
  echo -ne "\b\b\b\b... "; sleep .5; echo -ne "\b\b\b\b    "; sleep .5
    done
}

f_benchmachine()
{
    local ALPHAPROGRESS ALPHAPROGRESS2 ALPHAPROGRESS3 ALPHAPROGRESS4 BURN COUNTER PROGRESS SAMPLE SAMPLEb TEMPS TEMPS1 TEMPS2
    ALPHAPROGRESS=60 SAMPLE="sourceinstalled" # ! la taille du mot est importante ! ne pas modifier ! SAMPLE="sourceinstalled"
    ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
    f_burn()
    {
  CLOCKD=$(date +%s%N)
  while true
  do
      let COUNTER++; f_progress
      while true
      do
          let COUNTERb++; f_progress
          SAMPLEb="$SAMPLEb $(echo "$SAMPLE ")"
          [ $COUNTERb = 100 ] && break
      done
      unset -v COUNTERb
      echo $SAMPLEb|grep $SAMPLE|wc -w &>/dev/null
      [ $COUNTER = 10 ] && break
  done
  CLOCKF=$(date +%s%N)
  let BURN++
    }
    [ "$BURN" = "" ] && echo -n " [>] Benchmarking machine...  " && f_burn
    [ "$BURN" = "1" ] && unset -v COUNTER SAMPLEb && f_burn
    [ "$BURN" = "2" ] && TEMPS1=$(($CLOCKF-$CLOCKD)) && unset -v COUNTER SAMPLEb && f_burn
    TEMPS2=$(($CLOCKF-$CLOCKD)) TEMPS=$(($TEMPS1+$TEMPS2))
    RATIO=$(echo "scale=20;$TEMPS/2/$COUNTER/240000000"|bc|mawk '{printf "%0.1f\n",$1}')
    ## ($RATIO=1 est obtenu sur mon portable Core2Duo T7250 2GHz 2Go RAM, $RATIO>1 sur une machine plus lente)
    ## le resultat peut etre faux sur un portable non branche ou si une autre application prend de la ressource
    echo "Ratio $(uname -n): $RATIO" > ~/.$PROGNAME/ratio
    f_clearline r 1 35
}

f_benchmark()
{
    [ -z "$RATIO" ] && f_benchmachine; echo -n " [>] Benchmarking...  "; local RESULTF PROGRESS COUNTER
    ## ALPHACOUNTER: determine un nombre de boucles proportionnellement inverse au nombre de paquets dans la source pondere par le ratio machine
    ## destine a adapter le temps de bench en prenant en compte $NPA et la vitesse de la machine
    PREALPHACOUNT=`echo "scale=20;1/$NPA*150000*1/(1/$NPA*(300+$NPA/2))*1.8"|bc`
    ALPHACOUNTER=`echo "scale=20;$PREALPHACOUNT/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
    [ `echo "scale=0; $ALPHACOUNTER<2"|bc` -eq 1 ] && ALPHACOUNTER=2
    CLOCKD=$(date +%s%N)
    for i in $INSTALLED
    do
  let COUNTER++; f_progress
  RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $i)"
  [ $COUNTER -eq $ALPHACOUNTER ] && break
    done
    CLOCKF=$(date +%s%N)
    TEMPS=$(($CLOCKF-$CLOCKD)) BENCHMASS=$(($NPA*$COUNTER)) BENCH=$(echo "scale=10;$TEMPS/$BENCHMASS"|bc)
    f_clearline r 1 30
}

f_estimate()
{
    ESTIMATE=$(echo "scale=10;$BENCH*$COMPUTEMASS"|bc)
    ESTIMATEHS=$(echo "scale=0;$ESTIMATE/1000000000"|bc)
    ESTIMATEHSBC=$(echo "scale=3;$ESTIMATE/1000000000"|bc)
    mn=0 ss=$ESTIMATEHS ms=$(echo "$ESTIMATEHSBC-$ss"|bc|cut -d '.' -f2)
    [ $ESTIMATEHS -gt 59 ] && mn=$(($ESTIMATEHS/60)) && ss=$(($ss-$mn*60))
    [ $ss -lt 10 ] && ss="0$ss"
    ESTIMATE=$(echo ""$mn"m"$ss"s"$ms"ms")
}

f_mkcache()
{
    trap 'jobs -p f_adv &>/dev/null && kill $(jobs -p f_adv); echo -e \
    "\a\n$PROGNAME > WARNING! The disk cache might be left in an inconsistent state!"; f_exit' 2 3 9 15
    ## determine s'il y a des nouvelles sources a traiter:
    for s in $SOURCES; do [ -f $CACHEDIR/sources/$s ] && continue; SOURCESNEWS="$SOURCESNEWS $s"; let TSOURCESM++; done
    ## determine si des sources ont ete desactivees, dans ce cas les archive:
    ## NB: les depots designes par les noms de code des versions (ex. lenny) seront archives au changement de version,
    ## ceux utilisant la terminologie stable, testing, unstable,... seront traites par f_updatecache
    for s in $(ls $CACHEDIR/sources/)
    do
  printf '%b\n' $SOURCES|grep -qxm 1 $s &>/dev/null || { mv -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/.deleted/$s; DEL="$DEL $s"; }
    done
    [ -n "$DEL" ] && echo && for d in $DEL; do echo " [>] Archivage de la source supprimée $d";\
    echo "$MACHINE $(date "+%F %T") source supprimée $d archivée" >> ~/.$PROGNAME/$MACHINE/history.txt; done
    [ -z "$TSOURCESM" -a -n "$DEL" ] && { unset -v DEL; echo; echo >> ~/.$PROGNAME/$MACHINE/history.txt
    read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR; return; }; [ -z "$TSOURCESM" ] && return
    echo
    echo " [>] Création du cache initial de paquets installés pour les nouvelles sources:"; echo
    time\
    for a in $SOURCESNEWS
    do
  ## supprime la source du repertoire .deleted si elle a ete reactivee
  [ -f $CACHEDIR/.old/sources/.deleted/$a ] && rm -f $CACHEDIR/.old/sources/.deleted/$a
  ## ecrit dans $CACHEDIR/sources/$a les noms des paquets installes qui ont une occurrence dans $SOURCESDIR$a
  local TIMEFORMAT=" »»»  réelle: %lR" PROGRESS CSOURCES; let CSOURCES++
  echo " [»] Traitement de la source ($CSOURCES/$TSOURCESM) $a"
  PRERESULT=$(grep "^Package: " $SOURCESDIR$a | mawk '{print $2}') NPA=$(echo $PRERESULT | wc -w) COMPUTEMASS=$(($NPA*$NINSTALLED))
  echo " [»] $NPA paquets dans la source, $NINSTALLED paquets installés sur $MACHINE"
  [ -z "$RATIO" ] && f_benchmachine
  ### ALPHAPROGRESS: alteration proportionnelle de l'indicateur de progresssion. Utilise le nombre inverse de $NPA, pondere par $RATIO
  PREALPHAPROG=`echo "scale=20;1/$NPA*(200+$NPA)*10"|bc`
  [ `echo "scale=20; $PREALPHAPROG<=11"|bc` -eq 1 ]\
  && ALPHAPROGRESS=`echo "scale=20;(($PREALPHAPROG-10)*10+$PREALPHAPROG-10)/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`\
  || ALPHAPROGRESS=`echo "scale=20;$PREALPHAPROG/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS<1"|bc` -eq 1 ] && ALPHAPROGRESS=1
  [ `echo "scale=0; $ALPHAPROGRESS>20"|bc` -eq 1 ] &&\
  ALPHAPROGRESS=`echo "scale=20;20+(-1/$ALPHAPROGRESS+$ALPHAPROGRESS)/$NPA/1*$NPA/10"|bc|mawk '{printf "%0.0f\n",$1}'`
  [ `echo "scale=0; $ALPHAPROGRESS>30"|bc` -eq 1 ] && ALPHAPROGRESS=30
  ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4))
  f_benchmark
  f_estimate
  [ "$ESTIMATEHS" -lt 120 ] && echo -n " [»] durée estimée de traitement: $ESTIMATE  "\
  || echo -n " [»] durée estimée de traitement: $ESTIMATE (début $(date +%T))  "
  time\
  for WORKAROUND in 1
  do
      for b in $INSTALLED
      do
    f_progress
    RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $b)"
      done
      f_clearline b 1 1
  done
  printf '%b\n' $RESULTF|sort -d > $CACHEDIR/sources/$a
  echo "$MACHINE $(date "+%F %T") nouvelle source $a ajoutée" >>~/.$PROGNAME/$MACHINE/history.txt
  RESULTFC=$(echo $RESULTF | wc -w)
  [ $RESULTFC -ne 0 ] && echo " [*] $RESULTFC occurrences" || echo " [×] pas d'occurrence"
  echo ; unset -v PROGRESS RESULTF
  [ $TSOURCESM = $CSOURCES ] && local TIMEFORMAT=" [»] durée totale de traitement: %lR" && unset -v DEL SOURCESNEWS TSOURCESM
    done
    echo >>~/.$PROGNAME/$MACHINE/history.txt; echo; echo; read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR
}

f_updatecache()
{
    mv -f $CACHEDIR/Installed $CACHEDIR/.old/ 2>/dev/null; printf '%b\n' $INSTALLED > $CACHEDIR/Installed
    [ -f $CACHEDIR/.old/Installed ] || { echo; return; }
    echo -e " [>] Mise à jour du cache    \c"; f_adv &
    ICHGE=$(echo $(diff -y --suppress-common-lines $CACHEDIR/.old/Installed $CACHEDIR/Installed))
    echo $ICHGE|grep -q "<" && ICHGE=`echo $ICHGE|mawk '{gsub("<","");print $0}'`
    echo $ICHGE|grep -q ">" && ICHGE=`echo $ICHGE|mawk '{gsub(">","");print $0}'`
    echo $ICHGE|grep -q "|" && ICHGE=`echo $ICHGE|mawk '{gsub("\|","");print $0}'`
    for i in $ICHGE
    do
  grep -qx $i $CACHEDIR/Installed && INEWS="$INEWS $i" || ISUPR="$ISUPR $i"
    done
    [ -n "$INEWS" ] && printf '%b\n' $INEWS > $CACHEDIR/Linews; [ -n "$ISUPR" ] && printf '%b\n' $ISUPR > $CACHEDIR/Lisupr
    f_updt()
    {
  mv -f $CACHEDIR/sources/* $CACHEDIR/.old/sources/ 2>/dev/null
  for s in $(ls $CACHEDIR/.old/sources/)
  do
      ## supprime du cache les occurrences desinstallees
      for r in $ISUPR
      do
    grep -vx "$r" $CACHEDIR/.old/sources/$s > $CACHEDIR/sources/$s; cp -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/$s
      done
      PRERESULT=$(grep "^Package: " $SOURCESDIR$s | mawk '{print $2}')
      cp -f $CACHEDIR/.old/sources/$s $CACHEDIR/sources/$s
      ## ajoute au cache les nouvelles occurrences installees si elles apparaissent dans la source sauf si elles y sont deja
      for n in $INEWS
      do
    grep -qxm 1 "$n" $CACHEDIR/sources/$s &>/dev/null && continue
    echo "$PRERESULT"|grep -xm 1 "$n" >> $CACHEDIR/sources/$s
      done
      printf '%b\n' $(echo $(sort -d $CACHEDIR/sources/$s)) > $CACHEDIR/sources/$s
  done
    }
    [ -z "$ISUPR" -a -z "$INEWS" ] || f_updt
    ## ajoute au cache les occurrences anciennement installees mais nouvelles dans la source (par exemple nouvellement presentes dans security)
    for s in $(ls $CACHEDIR/sources/)
    do
  PRERESULT=$(grep "^Package: " $SOURCESDIR$s | mawk '{print $2}')
  SOCC=$(printf '%b\n' $PRERESULT $INSTALLED|sort -d|uniq -d)
  NEWSOCC=$(printf '%b\n' $SOCC $(cat $CACHEDIR/sources/$s)|sort -d|uniq -u)
  [ -n "$NEWSOCC" ] && {
  for o in $NEWSOCC
  do
      grep -qxm 1 "$o" $CACHEDIR/sources/$s &>/dev/null && continue
      echo "$o" >> $CACHEDIR/sources/$s
  done
  printf '%b\n' $(echo $(sort -d $CACHEDIR/sources/$s)) > $CACHEDIR/sources/$s; }
    done
    rm -f $CACHEDIR/.old/sources/* 2>/dev/null; kill -s SIGUSR1 $(jobs -p f_adv); f_clearline r 1 35
    ## il est a noter que les paquets obsoletes (plus presents dans les sources) sont conserves dans le cache et analysables comme obsoletes
}

f_selectsources()
{
    unset -v RESUME TSOURCES
    ## formatage des sources pour la presentation, comptage des sources, presentation
    for a in $SOURCES
    do
  [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
  && SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}') $a"\
  || SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1}') $a"
  let TSOURCES++
    done
    echo " [>] $TSOURCES sources de paquets actuellement sélectionnées pour analyse:"
    echo ; unset -v TSOURCES
    printf ' [%b]\t» %b\n' $SOURCESP
    echo
    read -p " [¿] Sélectionner ou éliminer (préfixe «-») un motif pour filtrer, valider pour terminer: " MOTIF
    ## si le MOTIF est vide, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    [ "$MOTIF" = "" ] && SOURCESS=$SOURCES
    until [ "$MOTIF" = "" ]
    do
  MOTIFS="$MOTIFS $MOTIF"
  read -p " [¿] continuer la sélection des sources à analyser, valider pour terminer: " MOTIF
    done
    ## s'il n'y a que des eliminations, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES
    for m in $MOTIFS ; do MOTIFC="$(echo $m | cut -c 1) $MOTIFC" ; done
    MCM=$(printf '%b\n' $MOTIFC | grep -c "-") MC=$( printf '%b\n' $MOTIFC | grep -c "")
    [ "$MCM" = "$MC" ] && SOURCESS=$SOURCES
    ## boucle d'inclusion. La boucle interne permet de ne pas inclure une source deja presente (doublon)
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" != "-" ] && SELECT=$(printf '%b\n' $SOURCES | grep $MOTIF) || continue
  for s in $SELECT
  do
      [[ $(printf '%b\n' "$SOURCESS" | grep -w "$s") ]] && continue
      SOURCESS="$SOURCESS $s"
  done
    done
    ## boucle d'exclusion
    for MOTIF in $MOTIFS
    do
  MOTIFC=$(echo $MOTIF | cut -c 1)
  [ "$MOTIFC" = "-" ] && MOTIF=$(echo $MOTIF | cut -c 2-) && SOURCESS=$(printf '%b\n' $SOURCESS | grep -v $MOTIF)
    done
    SOURCES=$SOURCESS
    echo
    ## exclusion des fichiers qui ne sont pas des descripteurs de paquets
    echo " [>] Analyse des sources:"
    [ "$SOURCES" != "" ] && NSOURCES=$(printf '%b\n' $SOURCES | grep -c "") || NSOURCES=0
    for a in $SOURCES
    do
  if ! grep -qm 1 "^Package: " $SOURCESDIR$a
  then
      [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\
      && b=$(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}')\
      || b=$(ls -sh $SOURCESDIR$a | mawk '{print $1}')
      echo " [×] non pertinente: $a [$b]"
      continue
  fi
  SOURCESC="$SOURCESC $a" ; let TSOURCES++
    done
    SOURCES="$SOURCESC"; unset -v MOTIFC MOTIFS SOURCESC SOURCESP SOURCESS
    [ "$SOURCES" = "" ] && TSOURCES=0
    [ "$TSOURCES" != "0" ]\
    && SOURCES=$(printf '%b\n' $SOURCES|sort -d) SOURCES=$(echo $SOURCES)\
    && echo " [»] $TSOURCES sources sur $NSOURCES à traiter dans la sélection:" && printf ' [*] [%b]\n' $SOURCES\
    || echo " [»] pas de sources à traiter dans la sélection"
    echo
    while true; do let COUNT++; echo ${FUNCNAME[$COUNT]}|grep -qx main && MAIN=$COUNT && unset -v COUNT && break; done
    RESUME=* ; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    while true
    do
  case "$RESUME" in
      q|Q) f_exit; RESUME=*;;
      h)  less $0; RESUME=*;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break $MAIN; };;
      p)  [ "$TSOURCES" != "0" ] && $CLEAR && echo && f_selectsources || RESUME=r;;
      l|L|"") [ "$TSOURCES" != "0" ] && break || [ "$RESUME" = "" ] && RESUME=r || RESUME=*;;
      r|R) $CLEAR; f_init; f_selectsources;;
      *)  [ "$TSOURCES" != "0" ]\
    && read -s -n 1 -p " [¿] Préciser encore la sélection - Recommencer - Lancer l'analyse <p/r/L>: " RESUME\
    && f_clearline r 1 104
    [ "$TSOURCES" = "0" ] && read -s -n 1 -p " [¿] Recommencer <R>: " RESUME && f_clearline r 1 50;;
  esac
    done
}

f_occm()
{
    while true
    do
  read -s -n 1 -p " [¿] Par la suite traiter aussi les sources sans occurrences ? <o/N>: " SELECT
  f_clearline r 1 75
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break 2; };;
      o|O)  OCCLESS=0; unset -v SELECT; $CLEAR; echo; break;;
      n|N|"") OCCLESS=1; unset -v SELECT; $CLEAR; echo; break;;
  esac
    done
}

f_squeezecache()
{
    for s in $SOURCES
    do
  local CSOURCES CSOURCESM CSOURCESS ; let CSOURCES++ ; let CSOURCESS++
  RESULTF=$(cat $CACHEDIR/sources/$s) RESULTFC=$(echo $RESULTF | wc -w)
  ## eval interprete l'item suivant dans la liste comme une commande s'il y a un espace
  RESULTF=`echo $RESULTF|mawk '{gsub(" ","¿");print $0}'`
  ## attribution d'une variable dynamique au resultat individuel - utilisation de eval
  ## identification par le n° de traitement $CSOURCES, attribution du contenu de RESULTF a la nouvelle variable
  ## la nouvelle variable recoit le nom de la source en alias, permet la concordance n°/nom
  [ $RESULTFC -ne 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [*] $RESULTFC occurrences\t$s"
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\
  && echo -e " [×] pas d'occurrence\t$s" && let CSOURCESM++
  [ $RESULTFC -eq 0 -a $OCCLESS -eq 1 ] && let CSOURCES-- && echo -e " [×] pas d'occurrence\t$s"
  unset -v RESULTF
    done
    echo ; TSOURCES=$CSOURCES ; [ -z $CSOURCESM ] && CSOURCESM=0
    echo " [»] $(($CSOURCES - $CSOURCESM)) sources sur $CSOURCESS présentent des occurrences de paquets installés sur $MACHINE"
    echo ; unset -v CSOURCESM CSOURCESS CSOURCES
    ## concatenation des resultats individuels - utilisation de la substitution de variable {!RESULTF}
    for (( n=1; n <= TSOURCES; n++ ))
    do
  RESULTF=RESULTF$n ## RESULTF se substitue a la variable dynamique dont le contenu est appele par {!RESULTF}
  RESULTFP=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTFP=$(echo $RESULTFP)
  RESULTFT="$RESULTFT $RESULTFP" ## concatenation, doublons compris elimines par sort -u par la suite
  SOURCESN="$SOURCESN $n" ## extrait les numeros des sources disponibles de 1 a n sources
    done
    SOURCESN=$(echo $SOURCESN) SOURCESNP=`echo $SOURCESN|mawk '{gsub(" ","\&|");print $0}'`
    RESULTFTS=$(printf '%b\n' $RESULTFT | sort -d) RESULTFTU=$(echo $(printf '%b\n' $RESULTFT | sort -u))
    RESULTFTC=$(echo $RESULTFT|wc -w) RESULTFTUC=$(echo $RESULTFTU|wc -w) RESULTFTCC=$(($RESULTFTC-$RESULTFTUC))
    UNKNOWNS=$(printf '%b\n' $INSTALLED $RESULTFTU|sort -d|uniq -u) UNKNOWNC=$(echo $UNKNOWNS|wc -w)
    NOPURGE=`dpkg --admindir=$INSTALLDIR -l|grep "^rc "|mawk '{print $2}'` NOPURGEC=$(echo $NOPURGE|wc -w)
    LINEWSC=$(cat $CACHEDIR/Linews 2>/dev/null|wc -w); LISUPRC=$(cat $CACHEDIR/Lisupr 2>/dev/null|wc -w)
    LINEWS=$(printf ' [%b]' $(cat $CACHEDIR/Linews 2>/dev/null)) LISUPR=$(printf ' [%b]' $(cat $CACHEDIR/Lisupr 2>/dev/null))
    echo
    echo " [*] paquets installés sur $MACHINE: $NINSTALLED"
    echo " [*] occurrences installées sur $MACHINE: $RESULTFTUC"
    echo " [*] paquets installés non analysés: $(($NINSTALLED-$RESULTFTUC))"
    echo " [*] croisements d'occurrences: $RESULTFTCC"
    echo " [*] occurrences totales: $RESULTFTC"
    echo
}

f_postproc()
{
    f_fmt() { fmt -w $(tput cols); }
    f_tee() { [ $RECORD = 1 ] && tee -a $RECFILE || tee; }
    f_less() { [ $LESS = 1 ] && less -m~ || tee; }
    f_pager()
    {
  read -s -n 1 -p " [¿] afficher les occurrences avec Less - directement - ne pas afficher <L/d/n>: " PAGER
  f_clearline r 1 80 ; [ "$PAGER" = "d" -o "$PAGER" = "n" ] || PAGER=L ; PAGERM="\c"
  [ "$PAGER" = L ] && LESS=1 PAGERM="      [affichage dans le pager]" || LESS=0; [ "$PAGER" = n ] && PAGERM="      -------------------------"
    }

    f_dores()
    {
  for S in $S
  do
      RESULTF=RESULTF$S RESULTFALIAS=$(eval alias RESULTF$S | cut -d "'" -f2) ; [ "$1" = "-a" ] && return
      RESULTF=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTF=$(echo $RESULTF)
      RESULTFC=$(echo $RESULTF|wc -w) ; [ "$1" = "-r" ] && return
      OBSOLETES=OBSOLETES$S; OBSOLETES=`echo ${!OBSOLETES}|mawk '{gsub("¿"," ");print $0}'`
      OBSOLETES=$(echo $OBSOLETES); OBSOLETESC=$(echo $OBSOLETES|wc -w)
  done
    }
    f_obs()
    {
  [ -n "$OBSOLETESTC" ] && return
  echo -n " [»] traitement    "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for S in $SOURCESN
  do
      f_dores -r; unset -v OBSOLETES
      for p in $RESULTF
      do
    grep -qxm 1 "Package: $p" $SOURCESDIR$RESULTFALIAS\
    || OBSOLETES="$OBSOLETES¿$p" OBSOLETEST="$OBSOLETEST $p"
      done
      eval OBSOLETES$S="$OBSOLETES"
  done
  OBSOLETEST=$(printf '%b\n' $OBSOLETEST|sort -u) OBSOLETESTC=$(echo $OBSOLETEST|wc -w)
  for o in $OBSOLETEST
  do
      unset -v COUNTER NOBS
      for S in $SOURCESN
      do
    f_dores -r
    let COUNTER++; [ $COUNTER -eq 1 ]\
    && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
    && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
    && OBSOLETESTR="$OBSOLETESTR $o"
    LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS); [ -z "$LOC" ] && continue
    LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
    VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
    [ "$VERI" = "$VER" ] && NOBS=1
      done
      [ -n "$NOBS" ] && OBSOLETESTR=$(printf '%b\n' $OBSOLETESTR|grep -vx $o)
  done
  OBSOLETESTRC=$(echo $OBSOLETESTR|wc -w); unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }
    f_twin()
    {
  [ -n "$TWIN" -o -n "$SINGLE" ] && return
  echo -n " [»] traitement    "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv &
  for u in $RESULTFTU
  do
      unset -v COUNTER
      for s in $RESULTFTS
      do
    [[ "$u" != "$s" ]] && continue
    let COUNTER++
      done
      [[ "$COUNTER" < 2 ]] && SINGLE="$SINGLE $u" && continue
      TWIN="$TWIN $u"
      TWINP="$TWINP $COUNTER"¿"$u"
  done
  TWINC=$(echo $TWIN|wc -w) SINGLEC=$(echo $SINGLE|wc -w)
  TWINP=`printf ' %b\n' $TWINP|sort -d|mawk '{gsub("¿","×  ");print $0}'`
  SINGLEP=$(printf ' [%b]' $SINGLE) ; TWIND=$(printf '%b\n' $TWIN)
  unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22
    }

    f_displayg()
    {
  { echo; echo " [>] [$MACHINE] Occurrences globales:"; }|f_tee
  [ "$SOURCESG" = "" ] &&\
  for S in $SOURCESN;do f_dores -r;[ $RESULTFC -ne 0 ] && SOURCESG="$SOURCESG $RESULTFALIAS" && SOURCESNG="$SOURCESNG $S" && let SOURCESGC++
  done
  [ "$SOURCESG" = "" ] && { echo " [×] Aucune des sources analysées n'a d'occurrence installée sur $MACHINE"; echo -e "\n\n"; }|f_tee && return
  { echo " [»] $SOURCESGC sources analysées ont des occurrences installées sur $MACHINE:"; echo; }|f_tee
  for S in $SOURCESNG; do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"|f_tee; TTLOCC=$(($TTLOCC+$RESULTFC)); done
  f_obs
  NOSOURCEDC=$(($OBSOLETESTRC+$UNKNOWNC)) SOURCEDC=$(($RESULTFTUC-$OBSOLETESTRC))
  { echo " [*] total: $TTLOCC occurrences"; echo; echo " [*] $NINSTALLED paquets installés sur $MACHINE"
  echo " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées"
  echo " [*] dont $OBSOLETESTRC paquets obsolètes et $UNKNOWNC paquets d'origine inconnue"
  echo " [*] $SOURCEDC paquets installés présents dans les sources analysées:"; echo; }|f_tee ; unset -v TTLOCC
  f_pager
  [ "$SOURCEDP" = "" ] && SOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $RESULTFTU|sort -d|uniq -u))
  [ "$NOSOURCEDP" = "" ] && NOSOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $UNKNOWNS|sort -d))
  [ "$NOPURGEP" = "" ] && NOPURGEP=$(printf ' [%b]' $NOPURGE)
  [ $PAGER = L ] && { printf '\n%b\n' " [*] $SOURCEDC paquets installés présents dans les sources analysées:" "$SOURCEDP"|f_fmt
  [ $NOSOURCEDC -gt 0 ] && printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $LINEWSC -gt 0 ] && printf '\n%b\n' \
  " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt
  [ $LISUPRC -gt 0 ] && printf '\n%b\n' \
  " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; }|f_tee |f_less
  [ $PAGER = d ] && { echo "$SOURCEDP"|f_fmt; [ $NOSOURCEDC -gt 0 ] &&\
  printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt
  [ $LINEWSC -gt 0 ] && printf '\n%b\n' \
  " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt
  [ $LISUPRC -gt 0 ] && printf '\n%b\n' \
  " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt
  [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; } |f_tee
  [ $PAGER = n ] && echo -e "$PAGERM"|f_tee || echo -e "$PAGERM"; { echo ; echo; }|f_tee
  [ $TSOURCES -eq 1 ] && { [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo; } && return

  f_twin
  [ $TWINC -eq 0 ] && { echo " [×] aucun croisement d'occurrence de paquets installés sur $MACHINE entre les sources analysées"
  echo -e "\n\n"; }|f_tee && return
  { echo " [*] $SINGLEC occurrences uniques";echo " [*] $RESULTFTCC croisements d'occurrences";echo " [*] $TWINC occurrences croisées:"; }|f_tee
  f_pager
  [ $PAGER = L ] && { printf '\n%b\n%b\n\n%b' " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:" "$TWINP"
  printf '\n\n\n%b\n\n%b' " [*] $SINGLEC occurrences uniques:" "$SINGLEP"|f_fmt; }|f_tee |f_less && echo -e "\n$PAGERM"
  [ $PAGER = d ] && { echo -e "\n$TWINP";echo -e "\n";echo -e " [*] $SINGLEC occurrences uniques:\n";echo "$SINGLEP"|f_fmt; }|f_tee
  [ $PAGER = n ] && echo -e "\n$PAGERM"|f_tee
  [ $RECORD = 1 ] && echo -e "\n\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    f_display()
    {
  { echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo; }|f_tee
  { for (( S=1; S <= $TSOURCES; S++ )); do f_dores -r; echo $SELECTS|grep -w $S &>/dev/null
  [ $? -eq 0 ] && echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]" || echo " [×]";done; }|f_tee
  f_pager
  [ $PAGER != n  ] && f_obs &&\
  for S in $SELECTS
  do
      f_dores
      echo -e "\n [*] $RESULTFC occurrences installées présentes dans le cache de la source [$RESULTFALIAS]:"
      [ $RESULTFC -ne 0 ] && echo && printf ' [%b]' $RESULTF|f_fmt; echo
      [ $OBSOLETESC -ne 0 ] && echo " [*] dont $OBSOLETESC occurrences obsolètes:" && printf ' [%b]' $OBSOLETES|f_fmt && echo
  done |f_tee|f_less ; echo|f_tee
  [ $PAGER = n ] && echo -e "$PAGERM\n"|f_tee || echo -e "$PAGERM\n"; echo|f_tee
  { printf " [»] occurrences uniques et croisées des sources"; printf ' [%b]' $SELECTS; echo ":"; }|f_tee
  f_pager
  f_sort()
  {
      f_twin
      for S in $SELECTS
      do
    f_dores -r
    for r in $RESULTF
    do
        echo "$TWIND"|grep -qxm 1 "$r" &>/dev/null && MULTIX="$MULTIX $r" && continue
        UNIX="$UNIX $r"
    done
    UNIXC=$(echo $UNIX|wc -w) MULTIXC=$(echo $MULTIX|wc -w)
    echo -e "\n [$S] $RESULTFALIAS [$(($UNIXC+$MULTIXC)) occurrences]" ; echo
    [ $UNIXC -ne 0 ] && echo " [*] $UNIXC occurrences uniques:" && printf ' [%b]' $UNIX|f_fmt && echo
    [ $MULTIXC -ne 0 ] && echo " [*] $MULTIXC occurrences croisées:" && printf ' [%b]' $MULTIX|f_fmt && echo
    unset -v UNIX MULTIX
      done |f_tee |f_less ; echo -e "\n$PAGERM\n\n"
      [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo
  }
  [ $PAGER != n  ] && f_sort || echo -e "\n$PAGERM\n\n\n"|f_tee
    }
    f_displaym()
    {
  echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo
  for ((S=1;S<=TSOURCES;S++)); do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"; done; echo
  while true
  do
      read -p " [¿] afficher les occurrences pour $SOURCESNP (défaut &) <$SOURCESN>: " SELECTS
      case "$SELECTS" in
    q|Q) f_exit;;
    h)  less $0;;
    "") SELECTS=$SOURCESN ; $CLEAR ; f_display ; break;;
    *)  SELECTS=$(printf '%b\n' $SELECTS|sort -u) doit=1
        for s in $SELECTS; do echo $SOURCESN|grep -w $s &>/dev/null; [ $? -ne 0 ] && doit=0; done
        [ $doit -ne 0 ] && $CLEAR && f_display && break;;
      esac
  done
    }

    f_package()
    {
  { echo -e "\n [>] [$MACHINE] Analyse par paquets:\n"; echo " [»] analyse des occurrences croisées entre les sources analysées:"; }|f_tee
  f_twin
  f_x()
  {
      { echo " [*] $RESULTFTCC croisements d'occurrences"
      echo " [*] $TWINC occurrences croisées:"; echo; }|f_tee
      f_pager
      [ $PAGER = n  ] && echo -e "$PAGERM\n"|f_tee && return
      for x in $TWIN
      do
    [ -z "$COUNT" -a $PAGER = L ] && printf '%b\n%b\n\n'\
    " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:"
    let COUNT++; echo " [$COUNT] [$x]"; unset -v COUNTER
    for S in $SOURCESN
    do
        f_dores -r; let COUNTER++
        [ $COUNTER -eq 1 ]\
        && LOCI=$(grep -xnm 1 "Package: $x" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo -e " $VERI $STATI"\
        && for d in $(ls $CACHEDIR/.old/sources/.deleted/)
        do grep -qxm 1 "$x" $CACHEDIR/.old/sources/.deleted/$d && echo " présent dans la source supprimée $d"; done
        LOC=$(grep -xnm 1 "Package: $x" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $x && echo " obsolète dans $RESULTFALIAS"; true; } && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS"
    done
    echo
      done |f_tee |f_less ; unset -v COUNT COUNTER; echo -e "$PAGERM\n"
  }
  [ $TWINC -eq 0 ]&&echo -e " [×] aucun croisement d'occurrences de paquets installés sur $MACHINE entre les sources analysées\n"|f_tee||f_x

  echo -e "\n\n [»] analyse des paquets installés non présents dans les sources analysées:"|f_tee
  f_u()
  {
      echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { COUNT=0 TUNKNOWNS=$UNKNOWNS; [ $PAGER = L ] && echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"
      for u in $UNKNOWNS
      do
    unset -v COUNTER
    for d in $(ls $CACHEDIR/.old/sources/.deleted/)
    do
        grep -qxm 1 "$u" $CACHEDIR/.old/sources/.deleted/$d && { TUNKNOWNS=$(printf '%b\n' $TUNKNOWNS|grep -vx $u); let COUNTER++
        [ $COUNTER -eq 1 ] && { let COUNT++; echo -e "\n [$COUNT] [$u]"; }; echo " origine possible: source supprimée [$d]"; }
    done
   
      done
      [ $COUNT -gt 0 -a $COUNT -lt $UNKNOWNC ] && { echo -e \
      "\n [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $(($UNKNOWNC-$COUNT)) autres paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }\
      || { [ $COUNT -eq 0 ]&&echo " [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $UNKNOWNC paquets:"
      printf ' [%b]' $TUNKNOWNS|f_fmt; }; }|f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $UNKNOWNC -eq 0 ] && echo -e " [×] aucun paquet d'origine inconnue installé sur $MACHINE\n"|f_tee || f_u

  echo -e "\n\n [»] analyse des occurrences obsolètes dans le cache des sources analysées:"|f_tee
  f_obs
  f_o()
  {
      echo " [*] $OBSOLETESTC occurrences obsolètes:"|f_tee
      f_pager; [ $PAGER = n  ] && echo -e "\n$PAGERM\n"|f_tee && return
      { OBS=$OBSOLETESTC; echo; [ $PAGER = L  ] && { echo " [*] $OBSOLETESTC occurrences obsolètes:"; echo; }
      for o in $OBSOLETEST
      do
    let COUNT++; unset -v COUNTER NOBS
    for S in $SOURCESN
    do
        f_dores -r
        let COUNTER++; [ $COUNTER -eq 1 ] && echo " [$COUNT] [$o]"\
        && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\
        && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\
        && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\
        && echo " $VERI $STATI" && OBSR="$OBSR $o"
        LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS)
        [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $o && echo " obsolète dans $RESULTFALIAS"; true; }\
        && continue
        LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15))
        VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "`
        printf ' %b %b\n' "$VER" "dans $RESULTFALIAS" ; [ "$VERI" = "$VER" ] && NOBS=1
    done
    [ -n "$NOBS" ] && { echo " [¡] la version installée de $o n'est PAS obsolète"; let OBS--; OBSR=$(printf '%b\n' $OBSR|grep -vx $o); }
    echo
      done
      [ $OBS -eq 0 ] && echo " [×] aucun des paquets installés sur $MACHINE n'est obsolète"\
      || { echo -e "\n [*] $OBS paquets installés sur $MACHINE sont obsolètes:"; printf ' [%b]' $OBSR|f_fmt; echo; }
      [ $UNKNOWNC -ne 0 ]\
      && echo " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes"
      } |f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n"
  }
  [ $OBSOLETESTC -eq 0 ] && { echo " [×] aucune occurrence obsolète de paquets installés sur $MACHINE dans les sources analysées"
  [ $UNKNOWNC -ne 0 ] &&\
  echo -e " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes\n\n"; } |f_tee || f_o
  [ $RECORD = 1 ] && echo -e "\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n"
    }

    echo
    [ $TSOURCES -eq 0 -a $OCCLESS -eq 1 ]\
    && echo " [>] Aucune des sources traitées ne présente d'occurrence en concordance avec les paquets installés sur $MACHINE"\
    && echo " [»] aucune analyse à effectuer" && echo && read -s -n 1 -p " [-] valider pour continuer... " && f_clearline r 1 35 && return 2
    echo " __________________________________________________________________________"
    echo " [-] Enregistrer la prochaine séquence - Aide - Accueil - Quitter <r/h/w/q>" ; RECORD=0 REC=""
    while true
    do
  read -s -n 1 -p " [¿]$REC [$MACHINE]: Analyse globale - Par sources - Par paquets <g/s/p>: " SELECT
  f_clearline r 1 110
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; return; };;
      r) REC=" [R]" RECORD=1;echo -e "\n\n $(date)" >>$RECFILE;;
      g) $CLEAR; f_displayg;break;;
      s) $CLEAR; f_displaym;break;;
      p) $CLEAR; f_package;break;;
  esac
    done
    f_postproc
}

f_home()
{
    [ -d ~/.$PROGNAME/$(uname -n) ] || { $CLEAR; echo -e "\n [>] Initialisation de $PROGNAME\n"; MACHINE=$(uname -n)
    f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }
    [ -d ~/.$PROGNAME/_alternate ] || { mkdir -p ~/.$PROGNAME/_alternate/
    echo "Copiez ici les répertoires /var/lib/apt/lists/ et /var/lib/dpkg/ d'un système alternatif que vous souhaitez analyser"\
    > ~/.$PROGNAME/_alternate/readme.txt; }

    $CLEAR; echo -e "\n\n\n\n\n\n"
    for w in Advanced  Packaging Tool DIAGnostic
    do
  NL=$(echo ${#w}) NLA=$NL; echo -n " "
  for ((l=1;l<=NL;l++))
  do
      L=$(echo $w|cut -c $l); echo $L|grep -q [A-Z] && L="\033[1m$L\033[0m"
      for ((la=NLA;la>=0;la--))
      do
    for ((s=la;s>=1;s--)); do SPACE="$SPACE "; done
    echo -ne "$SPACE$L "; NSPACE=$(echo ${#SPACE})
    unset -v SPACE; sleep 0.01; [ $NSPACE -eq 0 ] && break
    for ((b=1;b<=NSPACE+2;b++)); do echo -ne "\b"; done
      done
      NLA=$(($NLA-1))
      let INTER++; for ((s=2;s<=INTER/2;s++)); do echo -n " "; done
  done
  echo; unset -v INTER
    done
    echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n [>] $PROGNAME"; echo

    [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ] && { echo " [»] un système alternatif a été détecté"
    [ -w ~/.$PROGNAME/_alternate/lists/ -a -w ~/.$PROGNAME/_alternate/dpkg/ ]\
    || { echo -e "\a\n [!] la configuration alternative n'a pas les droits en écriture, sortie\n"; exit 1; }
    [[ $(ADM=~; dpkg --admindir=$ADM/.$PROGNAME/_alternate/dpkg/ -l 2>/dev/null) ]]\
    || { echo -e "\a\n [!] le répertoire ~/.$PROGNAME/_alternate/dpkg/ n'est pas une configuration valide pour dpkg, sortie\n"; exit 1; }
    read -p " [¿] nom du système: " MACHINE; f_clearline r 1 100
    MACHINE=$(echo $MACHINE|tr -d ".%$&|<>*\'\"# /\\" 2>/dev/null|tr "[A-Z]" "[a-z]"|sed 's/^-//')
    [ $(echo ${#MACHINE}) -gt 35 ] && echo " [!] $MACHINE: ce nom est déraisonnablement long..." && sleep 3 && f_clearline r 1 120 && return
    [ -d ~/.$PROGNAME/$MACHINE ] && echo " [!] $MACHINE: ce nom de système est déjà utilisé..." && sleep 3 && f_clearline r 1 100 && return
    read -s -n 1 -p " [¿] ce nom est-il correct: $MACHINE ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 100 && return
    $CLEAR; echo -e "\n [>] Initialisation du cache pour $MACHINE\n"; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; }

    echo " [»] systèmes analysables:"
    echo " [1] $(uname -n)"; COUNTER=1 MACHINES=1 MACHINESP=1; unset -v MACHINESUP MACHINESUPP
    for m in $(ls ~/.$PROGNAME/)
    do
  [ "$m" = "$(uname -n)" -o "$m" = "_alternate" ] && continue; [ -d ~/.$PROGNAME/$m ] || continue
  let COUNTER++; alias $COUNTER=$m; MACHINES="$MACHINES $COUNTER" MACHINESP="$MACHINESP/$COUNTER"
  MACHINESUP="$MACHINESUP $COUNTER" MACHINESUPP="$MACHINESUPP/$COUNTER"; echo " [$COUNTER] $m"
    done
    echo; unset -v COUNTER; echo " [-] Aide - Accueil - Quitter <h/w/q>"
    [ -n "$MACHINESUP" ] && MACHINESUPP=$(echo $MACHINESUPP|sed 's/^\///') &&\
    while true
    do
  read -s -n 1 -p " [¿] Sélectionner un système - Supprimer un système (défaut 1) <$MACHINESP/->: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h)  less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      -)  read -s -n 1 -p " [¿] sélectionner un système pour SUPPRESSION <$MACHINESUPP>: " SELECTM; f_clearline r 1 100
    echo $MACHINESUP|grep -w $SELECTM &>/dev/null\
    && { read -s -n 1 -p " [¿] supprimer $(alias $SELECTM|cut -d "'" -f2) de $PROGNAME ? <o/N>: " DEL; f_clearline r 1 100
    [ "$DEL" = o ] && rm -fr ~/.$PROGNAME/$(alias $SELECTM|cut -d "'" -f2); unset -v DEL; return; };;
      ""|1) MACHINE=$(uname -n); break;;
      *)  echo $MACHINES|grep -w $SELECT &>/dev/null && MACHINE=$(alias $SELECT|cut -d "'" -f2) && break;;
  esac
    done || MACHINE=$(uname -n); for m in $MACHINESUP; do unalias $m &>/dev/null; done
    while true
    do
  read -s -n 1 -p " [¿] [$MACHINE]: travailler sur l'ensemble des sources ? <O/n>: " SELECT
  f_clearline r 1 100
  case "$SELECT" in
      q|Q) f_exit;;
      h) less $0;;
      w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };;
      o|O|"") $CLEAR; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; OCCLESS=1; f_squeezecache; f_postproc; break;;
      n) $CLEAR; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; f_selectsources; f_occm; f_squeezecache; f_postproc; break;;
  esac
    done
}

while true; do f_home; done

Hors ligne

#21 23-06-2009 18:09:37

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : apt-diag et les paquets seront bien gardés

Ca suit ici... wink

Que veux dire ce résultat :

[*] paquets installés sur monpc: 1113
[*] occurrences installées sur  monpc: 1113
[*] paquets installés non analysés: 0
[*] croisements d'occurrences: 2325
[*] occurrences totales: 3438


Yop ?


"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#22 23-06-2009 23:56:08

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

smolski a écrit :

Que veux dire ce résultat :

[*] paquets installés sur monpc: 1113
[*] occurrences installées sur  monpc: 1113
[*] paquets installés non analysés: 0
[*] croisements d'occurrences: 2325
[*] occurrences totales: 3438


Ce sont des pré-résultats avant analyse. Je pourrais presque me passer de les afficher, mais ils peuvent déjà donner quelques indications sur le système si on sait bien les analyser, et accessoirement ils m'aident à débugger.

Sur les 1113 paquets installés, tous les paquets sont reconnus comme faisant partie du cache d'au moins une source (mais certains peuvent être obsolètes puisque le cache conserve les paquets obsolètes, ce qui est analysé plus loin dans le programme).

Croisement d'occurrence: nombre de fois où une occurrence apparaît moins le nombre d'occurrences uniques (ici 3438-1113=2325). Si chaque occurrence n'apparaît qu'une fois, il n'y a aucun croisement d'occurrence (ici on pourrait avoir 1113-1113=0). Si une occurrence apparaît deux foix on a 2-1 (le paquet installé)=1 croisement, si elle apparaît trois fois on a 3-1 (le paquet installé)=2 croisements. Si le nombre de croisements d'occurrences dépasse le nombre d'occurrences installées, on sait que certaines occurrences sont présentes dans plus de deux sources (comme c'est le cas ici). Mais tout ceci est analysé plus loin dans le programme.

Occurrence croisée: si une occurrence est présente dans mettons quatre sources, ça fait toujours une seule occurrence croisée. Le nombre de croisements d'occurrences est égal au nombre d'occurrences croisées si chaque occurrence croisée n'est présente que dans deux sources. Le nombre d'occurrences croisées est déterminé plus loin dans le programme (f_twin).

Occurrences totales: nombre total d'occurrences présentes dans le cache des sources (supérieur au nombre d'occurrences installées si il y a des occurrences croisées).

Occurrence: j'utilise ce terme pour distinguer des paquets installés qui par définition sont présents une et une seule fois sur le système. Une occurrence peut être présente dans plusieurs sources, et un paquet installé peut n'avoir aucune occurrence dans les sources. Le nombre d'occurrences installées est inférieur ou égal au nombre de paquets installés.


Bon, c'est un peu compliqué mais c'est que le problème n'est pas vraiment simple. Je pense cependant que la présentation des résultats est simple à appréhender, enfin j'espère parce que c'est un peu le but.

Vu le nombre d'occurrences totales que tu as par rapport au nombre de paquets installés, je dirais que tu as trois versions de distribution dans tes sources plus certainement un ou des dépôts security. Je ne peux pas en dire plus sans les résultats du programme.
L'analyse des occurrences croisées va être très longue, je te conseille d'appuyer sur 'R' avant de lancer le traitement pour enregistrer les résultats. Tu peux aussi obtenir des résultats intéressants en répondant non à «travailler sur l'ensemble des sources ?» et en choisissant une version de distribution en particulier (celle dont tu penses que la majorité des paquets proviennent), par exemple en filtrant avec squeeze ou testing ou sid... Et n'oublie pas que c'est à toi d'interpréter les résultats et de voir si ils correspondent ou non à ce que tu veux faire de ton système.

@+

Dernière modification par nofun (24-06-2009 00:01:35)

Hors ligne

#23 27-06-2009 18:07:34

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

Hors ligne

#24 04-07-2009 14:40:09

nofun
Membre
Lieu : Toulouse
Inscription : 22-04-2009

Re : apt-diag et les paquets seront bien gardés

Comme indiqué dans ce post, aptitude ne nettoie pas /var/lib/apt/lists/.

apt-diag se base justement sur le contenu de /var/lib/apt/lists/ pour déterminer les sources disponibles. Il est donc impératif d'effectuer un apt-get update après une upgrade de version de distribution (par exemple passage de Etch à Lenny) afin de ne pas se retrouver dans apt-diag avec des sources qui ne sont plus présentes dans /etc/apt/sources.list (ce qui entraîne nécessairement une multiplication des croisements d'occurrences).

Il n'est cependant pas interdit de conserver un temps ce /var/lib/apt/lists/ non nettoyé à des fins d'analyse, l'état réel étant rétabli au premier apt-get update.

Hors ligne

Pied de page des forums