Más Allá de Linux From Scratch: Versión 5.0 | ||
---|---|---|
Anterior | Capítulo 3. Configuración posterior al LFS | Siguiente |
Los programas para leer páginas de manual e info pueden procesar transparentemente páginas comprimidas con gzip o bzip2. Sin embargo, las cosas no son tan simples: los directorios man tienden a contener enlaces (duros o simbólicos) que arruinan ideas simples como la de ejecutar recursivamente gzip sobre ellos. Un método mejor es usar el siguiente guión.
cat > /usr/bin/compressdoc << "EOF" #!/bin/bash # VERSION: 20031029.0025 # # Comprime (con bzip2 o gzip) todas las páginas de manual de una # jerarquía y actualiza los enlaces simbólicos # - Por Marc Heerdink <marc @ koelkast.net> # Modificado por Mark Hymers <markh @ linuxfromscratch.org> # para poder escojer entre ficheros gzip o bzip2 y tratar correctamente # todos los enlaces simbólicos # # Modificado el 30/09/2003 por Yann E. Morin <yann.morin.1998 @ anciens.enib.fr> # para aceptar compresión/descompresión, manejar correctamente enlaces # duros, permitir el cambio de enlaces duros por blandos, especificar el nivel # de compresión, procesar man.conf para todas las apariciones de MANPATH, # permitir hacer copias de respaldo y permitir que se gu7arde la versión mas # reciente de una página. # # TODO: # - elegir el método de compresión por defecto basandose en la # herramienta disponible : gzip o bzip2; # - ofrecer una opción para elegir automáticamente el mejor método de # compresión según la página (por ejemplo, comprobar página a página # qué gzip/bzip2/lo que sea es mas efectivo); # - cuando exista una variable de entorno MANPATH, utilizarla en vez de # /etc/man.conf (útil para que los usuarios (des)compriman sus # páginas de manual); # - ofrecer una opción para recuperar una copia de respaldo anterior; # - añadir otras herramientas de compresión (compress, zip, etc?). # ¿Es necesario? # Bastante divertido, esta función muestra algo de ayuda. function help () { if [ -n "$1" ]; then echo "Opción desconocida : $1" fi ( echo "Uso: $0 <metodo_de_compresion> [opciones] [dirs]" && \ cat << EOT Donde metodo_de_compresion es uno de : --gzip, --gz, -g --bzip2, --bz2, -b Comprime utilizando gzip o bzip2. --decompress, -d Descomprime las páginas de manual. --backup Especifica que ha de hacerse un respaldo .tar para cada directorio. En caso de que un respalde exista, es salvado como .tar.old antes de hacer el nuevo respaldo. Si existe un respaldo .tar.old, este es eliminado antes de salvar el respaldo. En modo de respaldo no puede realizarse ninguna otra acción. Y donde las opciones són : -1 to -9, --fast, --best El nivel de copmpresión, tal y como lo aceptan gzip y bzip2. Cuando no se especifica, utiliza el nivel por defecto del método indicado (-6 para gzip y -9 para bzip2). No se utiliza en los modos de respaldo o descompresión. --force, -F Fuerza la (re-)compresión, incluso si el anterior tenía el mismo método. ütil cuando se cambia el nivel de compresión. Por defecto, una página no es recomprimida si termina en el mismo sufijo que que añade el método (.bz2 para bzip2, .gz para gzip). --soft, -S Cambia enlaces duros por enlaces blandos. Usar con cuidado, pues el primer fichero encontrado se usará como referencia. No se utiliza en modo de respaldo. --hard, -H Cambia enlaces blandos por enlaces duros. No se utiliza en modo de respaldo.. --conf=dir, --conf dir Especifica la localización de man.conf. Por defecto /etc. --verbose, -v Modo detallado, muestra el nombre del directorio que se está procesando. Dobla la opción para hecerle mas detallado y que muestre el nombre del fichero que se está procesando. --fake, -f Falsa ejecución. Muestra los parámetros actuales que se usarán. dirs Una lista de rutas absolutas a los directorios man separadas por espacios. Cuando está vacio, y solo entonces, procesa todas las apariciones de MANPATH en ${MAN_CONF}/man. Notas sobre la compresión Hubo una discusión en blfs-support sobre los niveles de compresión de gzip y bzip2 en las páginas de manual, teniendo en cuenta el sistema de ficheros anfitrión, la arquitectura, etc... Al final la conclusión fué que gzip es mucho mas eficiente sobre ficheros "pequeños" y bzip2 sobre ficheros "pequeños", siendo pequeño y grande muy dependiente del contenido de los ficheros. Mira el mensaje original de Mickael A. Peters, titulado "Bootable Utility CD", y fechado 20030409.1816(+0200), y los mensajes siguientes: http://linuxfromscratch.org/pipermail/blfs-support/2003-April/038817.html En mi sistema (x86, ext3), las páginas de manual tenían 35564kiB antes de comprimirlas. Comprimidas con gzip -9 bajaron a 20372kiB (57.28%), con bzip2 -9 bajaron a 19812kiB (55.71%). Esto es un ahorro de espacio del 1.57%. YMMV. Lo que no se tuvo en consideración fué la velocidad de descompresión. Pero, ¿esto tiene sentido?. U obtienes acceso rápido con página de manual sin comprimir, o ganas espacio a expensas de un ligero retardo de tiempo. Bien, mi P4-2.5GHz no llegó a percatarse de esto... :-) EOT ) | less } # Esta función comprueba que la página de manual es idéntica entre las # versiones bzip2, gzip y sin comprimir. # $1 es el directorio en el que reside el fichero # $2 es el nombre del fichero de la página de manual # Devuelve 0 (verdadera) si el fichero es mas reciente y debe tenerse en cuenta, # y 1 (falso) si el fichero no lo es (y por tanto debe borrarse) function check_unique () { # NB. Cuando hay enlaces duros a este fichero, estos no # son borrados. De hecho, si hay enlaces duros, todos ellos # tienen la misma fecha/hora, lo que los deja preparados para # borrarlos mas adelante. # Construye la lista con todas las páginas de manual que tienen # el mismo nombre DIR=$1 BASENAME=`basename "${2}" .bz2` BASENAME=`basename "${BASENAME}" .gz` GZ_FILE="$BASENAME".gz BZ_FILE="$BASENAME".bz2 # Busca y guarda la mas reciente 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 # En caso de que el fichero especificado sea el mas nuevo, devuelve 0 [ "$LATEST" = "$2" ] && return 0 # Si el fichero no es el mas nuevo, devuelve 1 return 1 } # OK, procesa los argumentos de la línea de comandos e inicializa un estado # algo sensible, esto es : no cambia el estado de los enlaces, procesa # /etc/man.conf, es mas silencioso, busca man.conf en /etc, y no fuerza la # (re-)compresión. 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\" no es el nombre absoluto de una ruta" exit 1 ;; esac done # Redirecciones case $VERBOSE_LVL in 0) # O, silencioso DEST_FD0=/dev/null DEST_FD1=/dev/null VERBOSE_OPT= ;; 1) # 1, algo detallado DEST_FD0=/dev/stdout DEST_FD1=/dev/null VERBOSE_OPT=-v ;; *) # 2 y superiores, es mas detallado DEST_FD0=/dev/stdout DEST_FD1=/dev/stdout VERBOSE_OPT="-v -v" ;; esac # Nota: en mi máquina, 'man --path' muestra /usr/share/man duplicado, # una vez con '/' al final, y otra si él. 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 no hay MANPATH en ${MAN_CONF}/man.conf, aborta el proceso if [ -z "$MAN_DIR" ]; then echo "Directorio no especificado y no encontrado con \`man --path'" exit 1 fi # ¿Falsa ejecución? if [ "$FAKE" != "no" ]; then echo "Parámetros actuales usados:" echo -n "Compresión.......: " case $COMP_METHOD in --bzip2|--bz2|-b) echo -n "bzip2";; --gzip|__gz|-g) echo -n "gzip";; --decompress|-d) echo -n "descompresión";; *) echo -n "desconocido";; esac echo " ($COMP_METHOD)" echo "Nivel de compresión.: $COMP_LVL" echo "Sufijo de compresión: $COMP_SUF" echo -n "Compresión forzada.: " [ "foo$FORCE_OPT" = "foo-F" ] && echo "si" || echo "no" echo "man.conf is.......: ${MAN_CONF}/man.conf" echo -n "Enlaces duros........: " [ "foo$LN_OPT" = "foo-S" ] && echo "convertir en blandos" || echo "dejarlos así" echo -n "Enlaces blandos........: " [ "foo$LN_OPT" = "foo-H" ] && echo "convertir en duros" || echo "dejarlos así" echo "Respaldo............: $BACKUP" echo "Falsa ejecución (!si!).....: $FAKE" echo "Directorios.......: $MAN_DIR" echo "Nivel de detalles...: $VERBOSE_LVL" exit 0 fi # Si no se especifica un método, mostrar la ayuda if [ -z "${COMP_METHOD}" -a "${BACKUP}" = "no" ]; then help exit 1 fi # En modo respaldo, hace solo el respaldo if [ "$BACKUP" = "yes" ]; then for DIR in $MAN_DIR; do cd "${DIR}/.." DIR_NAME=`basename "${DIR}"` echo "Backing up $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 # Sé que MAN_DIR solo contiene rutas absolutas. # Necesito tener en cuenta las páginas de manual localizadas, por lo # que lo hago recursivamente. for DIR in $MAN_DIR; do MEM_DIR=`pwd` cd "$DIR" for FILE in *; do # Corrige el caso en el que los directorios están vacios. if [ "foo$FILE" = "foo*" ]; then continue; fi # Corrige el caso en el que los enlaces duros ven el cambio en su esquema # de compresión (de sin comprimir a comprimidas, o de bzip2 a gzip o de # gzip a bzip2). También corrige el caso en el que hay presentes mútilples # versiones de la página, que pueden estar comprimidas o no. if [ ! -L "$FILE" -a ! -e "$FILE" ]; then continue; fi # No comprime los ficheros whatis if [ "$FILE" = "whatis" ]; then continue; fi if [ -d "$FILE" ]; then cd "${MEM_DIR}" # Regresa a donde ejecutamos "$0", en caso de que "$0"=="./compressdoc" ... # Vamos recursivamente a este directorio echo "-> Entrando a ${DIR}/${FILE}..." > $DEST_FD0 # No necesito usar --conf, pues especifico el directorio de trabajo. # Pero necesito salir en caso de error. "$0" ${COMP_METHOD} ${COMP_LVL} ${LN_OPT} ${VERBOSE_OPT} ${FORCE_OPT} "${DIR}/${FILE}" || exit 1 echo "<- Saliendo de ${DIR}/${FILE}." > $DEST_FD1 cd "$DIR" # Necesario para la siguiente iteración del bucle. else # !dir if ! check_unique "$DIR" "$FILE"; then continue; fi # Comprueba si el fichero ya está comprimido con el método especificado 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 tenemos un enlace simbólico. 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 # Cambia este enlace blando por uno duro rm -f "$FILE" && ln "${LINK}$COMP_SUF" "${FILE}$COMP_SUF" chmod --reference "${LINK}$COMP_SUF" "${FILE}$COMP_SUF" else # Mantiene este enlace como blando. rm -f "$FILE" && ln -s "${LINK}$COMP_SUF" "${FILE}$COMP_SUF" fi echo "Reenlazando $FILE" > $DEST_FD1 # En cambio, si tenemos un fichero plano. elif [ -f "$FILE" ]; then # Tiene en cuenta los enlaces duros: contruye la liste de ficheros enlazados # al que vamos a (des)comprimir. # NB. Esto no es óptimo pues el fichero será comprimido eventualmente # tantas vecese como enlaces duros tenga. Pero por ahora es la forma # mas segura. inode=`ls -li "$FILE" | awk '{print $1}'` HLINKS=`find . \! -name "$FILE" -inum $inode` if [ -n "$HLINKS" ]; then # ¡Tenemos enlaces duros! Los elimina ahora. for i in $HLINKS; do rm -f "$i"; done fi # Ahora tiene en cuanta los ficheros sin enlaces duros. # Los descomprimimos primero para comprimirlos mas tarde # con el nivel de compresión seleccionado... case "$FILE" in *.bz2) bunzip2 $FILE FILE=`basename "$FILE" .bz2` ;; *.gz) gunzip $FILE FILE=`basename "$FILE" .gz` ;; esac # Comprime el fichero con el nivel de compresión indicado, si es necesario. case $COMP_SUF in *bz2) bzip2 ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}" echo "Comprimiendo $FILE" > $DEST_FD1 ;; *gz) gzip ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}" echo "Comprimiendo $FILE" > $DEST_FD1 ;; *) echo "Sin comprimir: $FILE" > $DEST_FD1 ;; esac # Si el fichero tiene enlaces, los regenera (tanto duros como blandos) if [ -n "$HLINKS" ]; then for i in $HLINKS; do NEWFILE=`echo "$i" | sed s/\.gz$// | sed s/\.bz2$//` if [ "$LN_OPT" = "-S" ]; then # Hace este enlace duro uno blando. ln -s "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF" else # Mantiene el enlace duro como tal. ln "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF" fi chmod 644 "${NEWFILE}$COMP_SUF" # En realidad solo funciona con # enlaces duros. Inofensivo con # enlaces blandos. done fi else # Hay un problema cuando no obtenemos un enlace o un fichero plano. # Obviamente, nunca deberíamos llegar aquí... :-( echo "Whaooo... \"${DIR}/${FILE}\" no es un enlace o un fichero plano. Compruebalo:" ls -l "${DIR}/${FILE}" exit 1 fi fi done # para FILE done # para DIR EOF chmod 755 /usr/bin/compressdoc |
Ahora, como root, puedes ejecutar /usr/bin/compressdoc --bz2 para comprimir todas las páginas de manual de tu sistema. También puedes ejecutar /usr/bin/compressdoc --help para obtener una ayuda clara sobre lo que el guión puede hacer.
No olvide que algunos programas, como el sistema X Window o XEmacs, también instalan su documentación en lugares no estándares (como /usr/X11R6/man, etc...). No olvides añadir estas localizaciones al fichero /etc/man.conf con una sección MANPATH=/ruta.
Ejemplo:
... MANPATH=/usr/share/man MANPATH=/usr/local/man MANPATH=/usr/X11R6/man MANPATH=/opt/qt/doc/man ... |
Generalmente, los sistemas de instalación de paquetes no comprimen las páginas man/info, lo que significa que necesitarás ejecutar este guión otra vez si quieres mantener el tamaño de tu documentación tan pequeño como sea posible. Igualmente, ten en cuenta que es seguro ejecutar el guión tras actualizar un paquete: cuando tienes varias versiones de una página (por ejemplo, una comprimida y otra sin comprimir) la mas reciente es la que se guarda y las otras borradas..