Les programmes de lecture de pages man et peuvent traiter de manière transparente des pages compressées avec gzip et bzip, fonctionnalité intéressante pour gagner en espace disque tout en conservant votre documentation. Néanmoins, les choses ne sont pas aussi simple : les répertoires man ont tendance à contenir des liens, physiques et symboliques, qui empêchent les idées simples comme l'appel récursif de gzip. Une meilleur façon de faire est d'utiliser le script ci-dessous.
cat > /usr/sbin/compressdoc << "EOF" #!/bin/bash # VERSION: 20040320.0026 # # Compresse (avec bzip2 ou gzip) toutes les pages man dans un ensemble de # répertoires et met à jour les liens symboliques - Par Marc Heerdink <marc @ koelkast.net> # Modifiez pour être capable de compresser les fichiers avec gzip ou bzip2 # suivant une option et pour gérer tous les liens symboliques proprement par # Mark Hymers <markh @ linuxfromscratch.org> # # Modifié 20030930 par Yann E. Morin <yann.morin.1998 @ anciens.enib.fr> # pour accepter la compression/décompression, pour gérer correctement les liens # physiques, pour permettre la modification de liens physiques en liens # symboliques, pour spécifier le niveau de compression, pour analyser man.conf # pour toutes les occurrences de MANPATH, pour permettre une sauvegarde, pour # autoriser la conservation de la version la plus récente d'une page. # Modifié 20040330 par Tushar Teredesai pour remplacer $0 par le nom du script. # (Note: il est supposé que le script se trouve dans le chemin (PATH) de l'utilisateur) # # # TODO: # - choisir une méthode de compression par défaut suivant la # disponibilité des outils : gzip ou bzip2; # - offrir une option pour choisir automatiquement la meilleure méthode # de compression sur une base page par page (c'est-à-dire, vérifier # lequel des outils de compression, entre gzip/bzip2/autre, est le plus # performant, et ceci page par page); # - lorsque la variable d'environnement MANPATH existe, l'utilisez plutôt # que /etc/man.conf (utile pour les utilisateurs souhaitant # (dé)compresser leurs man pages; # - offrir une option pour restaurer une sauvegarde précédente; # - ajouter d'autres outils de compression (compress, zip, etc?). # Nécessaire? # Assez logiquement, cette fonction affiche de l'aide. function help () { if [ -n "$1" ]; then echo "Option inconnue : $1" fi ( echo "Usage: $MY_NAME <méthode_compression> [options] [dirs]" && \ cat << EOT Où méthode_compression est : --gzip, --gz, -g --bzip2, --bz2, -b Compresse en utilisant gzip ou bzip2. --decompress, -d Décompresse les pages man. --backup Spécifie qu'une sauvegarde .tar doit être faire pour chaque répertoire. Au cas où une sauvegarde existe déjà, elle est sauvegardée dans .tar.old avant de créer la nouvelle sauvegarde. Si une sauvegarde .tar.old existe, elle est supprimée avant de sauvegarder l'ancienne sauvegarde. En mode sauvegarde, aucune autre action n'est effectuée. Et où les options sont : -1 to -9, --fast, --best Le niveau de compression, telle que gérée par gzip et bzip2. Si elle n'est pas spécifiée, utilise le niveau de compression par défaut de la méthode donnée (-6 pour gzip, et -9 pour bzip2). Inutilisée en mode sauvegarde et en mode décompression. --force, -F Force la (re-)compression, même si l'ancien utilisait la même méthode. Utile lors d'un changement de niveau de compression. Par défaut, une page ne sera pas re-compressée si elle se termine avec le même suffixe que la méthode utilisée (.bz2 pour bzip2, .gz pour gzip). --soft, -S Modifie les liens physiques en liens symboliques. A utiliser avec précaution car le premier fichier rencontré sera utilisé comme référence. Inutilisée en mode sauvegarde. --hard, -H Modifie les liens symboliques en liens physiques. Inutilisée en mode sauvegarde. --conf=dir, --conf dir Spécifie l'emplacement de man.conf. Par défaut, /etc. --verbose, -v Mode verbeux, affiche le nom du répertoire en cours de traitement. Doublez l'option pour qu'elle soit encore plus verbeuse et pour qu'elle affiche le nom du fichier en cours de traitement. --fake, -f Mode émulation. Affiche les paramètres réels que compman utilisera. dirs Une liste de chemins absolus séparés par des espaces menant aux répertoires man. Si vide, et seulement dans ce cas, analyse ${MAN_CONF}/man.conf pour toutes les occurrences de MANPATH. Note sur la compression Il y a eu une discussion sur blfs-support concernant les niveaux de compression de gzip et bzip2 sur les pages man, en prenant en compte le système de fichiers hôte, l'architecture, etc... En résumé, la conclusion était que gzip était plus efficace sur les 'petits' fichiers, que bzip2 l'était sur les 'gros' fichiers, petit et gros dépendant beaucoup du contenu des fichiers. Voir le message original de Mickael A. Peters, intitulé "Bootable Utility CD", et daté de 20030409.1816(+0200), ainsi que les messages consécutifs: http://linuxfromscratch.org/pipermail/blfs-support/2003-April/038817.html Sur mon système (x86, ext3), les pages man faisaient 35564kiB avant compression. gzip -9 les a compressé pour arriver à 20372kiB (57,28%), bzip2 -9 arrivait à 19812kiB (55,71%). Cela représente un gain de 1,57%. YMMV. Ce qui n'a pas été pris en considération est le temps de décompression. Mais cela a-t'il aussi un sens ? Vous gagnez en rapidité d'accès avec des pages man non compressées ou vous gagnez de l'espace disque contre un léger contre-temps. En fait, mon P4-2.5GHz ne me permet même pas de l'apprécier... :-) EOT ) | less } # Cette fonction vérifie que la page man est unique parmi les versions bzip2, # gzip et non compressés. # $1 le répertoire où réside le fichier # $2 le nom du fichier de la page man # Renvoit 0 (true) si le fichier est le dernier et doit être pris en # considération et 1 (false) si le fichier n'est pas le dernier (et a donc été # supprimé). function check_unique () { # NB. Lorsqu'il y a des liens physiques vers ce fichier, ils ne sont _pas_ # supprimés. En fait, si ce sont des liens physiques, ils ont tous la même # date/heure, les préparant à la suppression plus tard. # Construit la liste de toutes les pages man de même nom DIR=$1 BASENAME=`basename "${2}" .bz2` BASENAME=`basename "${BASENAME}" .gz` GZ_FILE="$BASENAME".gz BZ_FILE="$BASENAME".bz2 # Recherche, et conserve, le plus récent LATEST=`(cd "$DIR"; ls -1rt "${BASENAME}" "${GZ_FILE}" "${BZ_FILE}" 2>/dev/null | tail -n 1)` for i in "${BASENAME}" "${GZ_FILE}" "${BZ_FILE}"; do [ "$LATEST" != "$i" ] && rm -f "$DIR"/"$i" done # Au cas où le fichier spécifié est le dernier, renvoit 0 [ "$LATEST" = "$2" ] && return 0 # Si le fichier n'est pas le dernier, renvoit 1 return 1 } # Nom du script MY_NAME=`basename $0` # OK, analyse les arguments de la ligne de commande et initialise à un état # particulier : ne pas modifier les liens, analyser /etc/man.conf, être le plus # silencieux, rechercher man.conf dans /etc et ne pas forcer la (re-)compression. COMP_METHOD= COMP_SUF= COMP_LVL= FORCE_OPT= LN_OPT= MAN_DIR= VERBOSE_LVL=0 BACKUP=no FAKE=no MAN_CONF=/etc while [ -n "$1" ]; do case $1 in --gzip|--gz|-g) COMP_SUF=.gz COMP_METHOD=$1 shift ;; --bzip2|--bz2|-b) COMP_SUF=.bz2 COMP_METHOD=$1 shift ;; --decompress|-d) COMP_SUF= COMP_LVL= COMP_METHOD=$1 shift ;; -[1-9]|--fast|--best) COMP_LVL=$1 shift ;; --force|-F) FORCE_OPT=-F shift ;; --soft|-S) LN_OPT=-S shift ;; --hard|-H) LN_OPT=-H shift ;; --conf=*) MAN_CONF=`echo $1 | cut -d '=' -f2-` shift ;; --conf) MAN_CONF="$2" shift 2 ;; --verbose|-v) let VERBOSE_LVL++ shift ;; --backup) BACKUP=yes shift ;; --fake|-f) FAKE=yes shift ;; --help|-h) help exit 0 ;; /*) MAN_DIR="${MAN_DIR} ${1}" shift ;; -*) help $1 exit 1 ;; *) echo "\"$1\" n'est pas un chemin absolu" exit 1 ;; esac done # Redirections case $VERBOSE_LVL in 0) # O, être silencieux DEST_FD0=/dev/null DEST_FD1=/dev/null VERBOSE_OPT= ;; 1) # 1, être un peu verbeux DEST_FD0=/dev/stdout DEST_FD1=/dev/null VERBOSE_OPT=-v ;; *) # 2 et au-dessus, être très verbeux DEST_FD0=/dev/stdout DEST_FD1=/dev/stdout VERBOSE_OPT="-v -v" ;; esac # Note: sur ma machine, 'man --path' donne /usr/share/man deux fois, une fois # avec un '/' en fin, une fois sans. if [ -z "$MAN_DIR" ]; then MAN_DIR=`man --path -C "$MAN_CONF"/man.conf \ | sed 's/:/\\n/g' \ | while read foo; do dirname "$foo"/.; done \ | sort -u \ | while read bar; do echo -n "$bar "; done` fi # Si aucun MANPATH dans ${MAN_CONF}/man.conf, annuler tout if [ -z "$MAN_DIR" ]; then echo "Aucun répertoire spécifié et aucun répertoire trouvé avec \`man --path'" exit 1 fi # Faux? if [ "$FAKE" != "no" ]; then echo "Paramètres utilisés:" echo -n "Compression........: " case $COMP_METHOD in --bzip2|--bz2|-b) echo -n "bzip2";; --gzip|__gz|-g) echo -n "gzip";; --decompress|-d) echo -n "décompression";; *) echo -n "unknown";; esac echo " ($COMP_METHOD)" echo "Niveau de compression.: $COMP_LVL" echo "Suffixe de compression: $COMP_SUF" echo -n "Forcer la compression: " [ "foo$FORCE_OPT" = "foo-F" ] && echo "yes" || echo "no" echo "man.conf est..........: ${MAN_CONF}/man.conf" echo -n "Hard-links............: " [ "foo$LN_OPT" = "foo-S" ] && echo "convert to soft-links" || echo "leave as is" echo -n "Liens symboliques.....: " [ "foo$LN_OPT" = "foo-H" ] && echo "convert to hard-links" || echo "leave as is" echo "Sauvegarde............: $BACKUP" echo "Faux (oui!)...........: $FAKE" echo "Répertoires...........: $MAN_DIR" echo "Niveau de verbosité...: $VERBOSE_LVL" exit 0 fi # Si aucune méthode n'a été spécifiée, affichez l'aide if [ -z "${COMP_METHOD}" -a "${BACKUP}" = "no" ]; then help exit 1 fi # En mode sauvegarde, faire uniquement la sauvegarde if [ "$BACKUP" = "yes" ]; then for DIR in $MAN_DIR; do cd "${DIR}/.." DIR_NAME=`basename "${DIR}"` echo "Sauvegarde de $DIR..." > $DEST_FD0 [ -f "${DIR_NAME}.tar.old" ] && rm -f "${DIR_NAME}.tar.old" [ -f "${DIR_NAME}.tar" ] && mv "${DIR_NAME}.tar" "${DIR_NAME}.tar.old" tar cfv "${DIR_NAME}.tar" "${DIR_NAME}" > $DEST_FD1 done exit 0 fi # Je sais que MAN_DIR n'a que des noms de chemins absolus # Je dois prendre en considération les pages man localisées, donc je deviens # récursif for DIR in $MAN_DIR; do MEM_DIR=`pwd` cd "$DIR" for FILE in *; do # Corrige le cas où le répertoire est vide if [ "foo$FILE" = "foo*" ]; then continue; fi # Corrige le cas où les liens symboliques voient leur schéma de compression # changé (de non compressé à compressé, ou de bz2 à gz, ou de gz à bz2) # Corrige aussi le cas où plusieurs versions de la page sont présentes, # compressées ou non. if [ ! -L "$FILE" -a ! -e "$FILE" ]; then continue; fi # Ne compresse pas les fichiers whatis if [ "$FILE" = "whatis" ]; then continue; fi if [ -d "$FILE" ]; then cd "${MEM_DIR}" # Retourne en arrière où nous avons lancé "$0", au cas où "$0"=="./compressdoc" ... # Nous devenons récursif pour ce répertoire echo "-> Entering ${DIR}/${FILE}..." > $DEST_FD0 # Je ne dois pas passé --conf, car je spécifie le répertoire de travail # Mais je dois sortir en cas d'erreur "$MY_NAME" ${COMP_METHOD} ${COMP_LVL} ${LN_OPT} ${VERBOSE_OPT} ${FORCE_OPT} "${DIR}/${FILE}" || exit 1 echo "<- Sortie de ${DIR}/${FILE}." > $DEST_FD1 cd "$DIR" # Nécessaire pour la prochaine itération de la boucle else # !dir if ! check_unique "$DIR" "$FILE"; then continue; fi # Vérifie si le fichier est déjà compressé avec la méthode spécifiée BASE_FILE=`basename "$FILE" .gz` BASE_FILE=`basename "$BASE_FILE" .bz2` if [ "${FILE}" = "${BASE_FILE}${COMP_SUF}" -a "foo${FORCE_OPT}" = "foo" ]; then continue; fi # Si nous avons un lien symbolique if [ -h "$FILE" ]; then case "$FILE" in *.bz2) EXT=bz2 ;; *.gz) EXT=gz ;; *) EXT=none ;; esac if [ ! "$EXT" = "none" ]; then LINK=`ls -l "$FILE" | cut -d ">" -f2 | tr -d " " | sed s/\.$EXT$//` NEWNAME=`echo "$FILE" | sed s/\.$EXT$//` mv "$FILE" "$NEWNAME" FILE="$NEWNAME" else LINK=`ls -l "$FILE" | cut -d ">" -f2 | tr -d " "` fi if [ "$LN_OPT" = "-H" ]; then # Modifie le lien symbolique en lien physique rm -f "$FILE" && ln "${LINK}$COMP_SUF" "${FILE}$COMP_SUF" chmod --reference "${LINK}$COMP_SUF" "${FILE}$COMP_SUF" else # Modifie le lien physique en lien symbolique rm -f "$FILE" && ln -s "${LINK}$COMP_SUF" "${FILE}$COMP_SUF" fi echo "Modification du lien $FILE" > $DEST_FD1 # Sinon, nous avons un fichier standard elif [ -f "$FILE" ]; then # Prenons en considération les liens physiques: construire la liste des # liens physiques allant sur le fichier que nous sommes en train de # {dé,}compresser. # NB. Ceci n'est pas optimum car le fichier sera éventuellement # compressé autant de fois qu'il a de liens compressés. Mais, pour # l'instant, c'est le moyen le plus sûr. inode=`ls -li "$FILE" | awk '{print $1}'` HLINKS=`find . \! -name "$FILE" -inum $inode` if [ -n "$HLINKS" ]; then # Nous avons de liens physiques! A supprimer maintenant. for i in $HLINKS; do rm -f "$i"; done fi # Maintenant, occupons-nous du fichier qui n'a pas de liens physiques # Nous décompressons avant de re-compresser avec le niveau de # compression sélectionné précédemment... case "$FILE" in *.bz2) bunzip2 $FILE FILE=`basename "$FILE" .bz2` ;; *.gz) gunzip $FILE FILE=`basename "$FILE" .gz` ;; esac # Compresse le fichier avec le taux de compression indiqué si nécessaire case $COMP_SUF in *bz2) bzip2 ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}" echo "$FILE compressé " > $DEST_FD1 ;; *gz) gzip ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}" echo "$FILE compressé " > $DEST_FD1 ;; *) echo "$FILE non compressé " > $DEST_FD1 ;; esac # Si le fichier a des liens physiques, nous devons les recréer (soit en # physique soit en symbolique) if [ -n "$HLINKS" ]; then for i in $HLINKS; do NEWFILE=`echo "$i" | sed s/\.gz$// | sed s/\.bz2$//` if [ "$LN_OPT" = "-S" ]; then # Modifie ce lien symbolique en lien physique ln -s "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF" else # Modifie ce lien physique en lien symbolique ln "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF" fi chmod 644 "${NEWFILE}$COMP_SUF" # Really work only for hard-links. Harmless for soft-links done fi else # Il reste un problème où nous n'avons ni un lien symbolique ni un lien # physique # Evidemment, nous ne devrions jamais arriver là... :-( echo "Whaooo... \"${DIR}/${FILE}\" n'est ni un lien symbolique ni un lien physique. Merci de vérifier:" ls -l "${DIR}/${FILE}" exit 1 fi fi done # for FILE done # for DIR EOF chmod 755 /usr/sbin/compressdoc
Maintenant, en tant qu'utilisateur root, vous pouvez lancer compressdoc --bz2 pour compresser toutes les pages man de votre système. Vous pouvez aussi lancer compressdoc --help pour obtenir une aide compréhensible sur ce que le script est capable de faire.
N'oubliez que certains programmes, comme le système X Window et XEmacs, installent aussi leur documentation dans des emplacements non standard (tels que /usr/X11R6/man, etc...). N'oubliez pas d'ajouter ces emplacements dans le fichier /etc/man.conf, comme une section MANPATH=/path.
Exemple:
... MANPATH=/usr/share/man MANPATH=/usr/local/man MANPATH=/usr/X11R6/man MANPATH=/opt/qt/doc/man ...
Habituellement, les systèmes d'installation de packages ne compressent pas les pages man/info, ce qui signifie que vous aurez besoin de lancer le script de nouveau su vous souhaitez conserver la taille de votre documentation le plus bas possible. De même, notez que lancer le script après avoir mis à jour un package est sûr : quand vous avez plusieurs versions d'une page (par exemple, une compressée et une non compressée), la plus récente est conservée et l'autre est supprimée.