Наши партнеры








Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux
Beyond Linux From Scratch. Version 2011-12-30
Назад 3. Завершающие настройки в системе LFS Вперед

Сжатие страниц Man и Info

Поскольку программы, читающие страницы руководств man и info, могут прозрачно обрабатывать файлы, сжатые с помощью программ gzip и bzip2, эта возможность поможет вам освободить немного дискового пространства в случае, если вы храните документацию на диске. Ноне все так просто: в каталогах man, как правило, есть ссылки — жесткие и символические, которые мешают воспользоваться для сжатия таким простым решением, как рекурсивный вызов команды gzip. Поэтому лучше воспользуйтесь скриптом, который приведен ниже. Если вы предпочитаете скачивать файлы, а не набирать их или копировать их содержимое через буфер обмена, вы можете скачать файл с этим скриптом по ссылке http://anduin.linuxfromscratch.org/files/BLFS/svn/compressdoc (файл должен быть установлен в каталог /usr/sbin).

cat > /usr/sbin/compressdoc << "EOF"
#!/bin/bash
# VERSION: 20080421.1623
#
# Сжатие (с помощью bzip2 или gzip) всех страниц man в иерархии и 
# обновление символических ссылок - автор Marc Heerdink <marc @ koelkast.net>
#
# Обновлено для возможности указывать файлы gzip или bzip2 в качестве параметров и 
# правильной обработки символических ссылок - Mark Hymers <markh @ linuxfromscratch.org>
#
# Изменено 20030930 (автор - Yann E. Morin <yann.morin.1998 @ anciens.enib.fr>
# для возможности сжимать/разархивировать, правильно обрабатывать жеские ссылки,
# изменять жесткие ссылки символическми ссылками, указывать
# уровень сжатия, аналихзировать man.conf на наличие всех вхождений переменных MANPATH,
# позволять выполнять резервное копирование и сохранять новые версии страницы.
#
# Изменено 20040330 (автор - Tushar Teredesai) чтобы заменить параметр $0 именем
# скрипта.
#   (Замечание: Предполагается, что скрипт указан в пользовательском пути PATH)
#
# Изменено 20050112 (автор - Randy McMurchy) чтобы сократить длину строки 
# и исрпавить грамматические ошибки.
#
# Изменено 20060128 (автор - Alexander E. Patrakov) для совместимости с Man-DB.
#
# Изменено 20060311 (автор - Archaic) чтобы использовать утилиту Man-DB manpath, 
# которая заменяет команду man --path из Man.
#
# Изменено 20080421 (автор - Dan Nicholson) чтобы правильно выполнять correct
# compressdoc когда работа выполняется рекурсивно. Это означает, что та же самая команда compressdoc
# будет использоваться везде, где можно использовать значения получаемые из переменной PATH.
#
# Изменено 20080421 (автор - Dan Nicholson) чтобы более правильно поступать с директориями,
# которых нет или для работы с которыми недостаточно прав доступа.
#
# Изменено 20080421 (автор - Lars Bamberger) чтобы исходя из размера 
# страницы автоматически выбирать метод сжатия. В добавок  Dan Nicholson  
# исправил несколько ошибок.
#
# Изменено 20080421 (автор - Dan Nicholson) чтобы подавить предупреждения из manpath
# порскольку они выдаются, когда задана переменная $MANPATH. Удалено TODO для 
# переменной $MANPATH поскольку обработка manpath(1) уже сделана.
#
# TODO:
#     - выбирать метод сжатия, ипользуемый по умолчанию с учетом имеющегося 
#       инструментального средства: gzip or bzip2;
#     - предлагается параметр для восстановления предыдущей резервной копии;
#     - добавить другие движки сжатия (compress, zip, etc?). Нужно?

# Эта функцмия выдает некоторую подсказку.
function help ()
{
  if [ -n "$1" ]; then
    echo "Unknown option : $1"
  fi
  ( echo "Использование: $MY_NAME <метод_сжатия> [параметры] [директории]" && \
  cat << EOT
Где в качестве <метод_сжатия> используется один их следующих вариантов:
  --gzip, --gz, -g
  --bzip2, --bz2, -b
                Сжатие с использованием gzip или bzip2.
  --automatic
                Сжатие с использованием gzip или bzip2 в зависимости от размера файла,
                который сжимается. Файлы, размер которых больше 5 kB, сжимаются с помощью 
                bzip2, Файлы, размер которых больше 1 kB сжимаются с помощью 
                gzip, а файлы, размер которых меньше 1 kB, не сжимаются.

  --decompress, -d
                Разархивирование страниц man.

  --backup      Расширение .tar будет сделано для резервной копии любого директория.
                В случае, если резервная копия уже существует, то перед тем, как будет 
                сделана новая копия, сатрарая копия будет сохранена с расширением 
                .tar.old. Если копися с расширением .tar.old существует, то она будет 
                удалена перед сохранением новой резервной копии. В режиме создания 
                резервных копий никакие другие дейстывия не выпоняются.

И где в качестве [параметры] используются:
  -1 to -9, --fast, --best
                Уровень сжатия, используемый в gzip и bzip2. Когда не указан, то 
                используется уровень сжания, определенный по умолчанию для данного 
                метода (-6 для gzip и -9 для bzip2). Не используется в режиме
                создания резервной копии или в режиме распаковки.

  --force, -F   Форсированное (пере-)сжатие даже в том случае, если в предыдущий раз
                был использован тот же самый способ сжатия. Используется, когда 
                изменяется степень сжатия. По умолчанию страница не будет пересжиматься 
                в случае, если расширение файла арживной копии соотвествует выбранному 
                способу архивирования (.bz2 для bzip2, .gz для gzip).

  --soft, -S    Преобразование жестких ссылок в символические. Используйте с _осторожностью_
                поскольку все ссылки будут делаться относительно первого встретившегося 
                фалйа. Не используется в режиме создания резервной копии.

  --hard, -H    Преоюбразование символических ссылок в жесткие ссылки. Не используется 
                в режиме создания резервной копии.

  --conf=dir, --conf dir
                Указывает месторасположение файла man_db.conf. По 
                умолчанию находится в /etc.

  --verbose, -v Режим подробной выдачи информации. выдается имя обрабатываемого 
                директория. Двойное указание флага выдает еще больше информации - выдается 
                имя обрабатываемого файла.

  --fake, -f    Выдаются параметры, которые будут фактически использоваться в 
                compressdoc.

  dirs          Список _абсолютных_ путей к директоириям man,   разделенных символом пробела. 
                Когда список пустой и только тогда, используйте manpath для анализа 
                ${MAN_CONF}/man_db.conf для всех допустимых вхождений MANDATORY_MANPATH.

Замечание, касающиеся сжатия:
  На blfs-support была дискуссия о степени сжатия станиц man с помощью 
  gzip и bzip2 с учетом используемой файловой системы, архитектуры и 
  т.д. В итоге было выяснено, что сжатие с помощью gzip более 
  эффективно с 'небольшими' файлами, а bzip2 - с 'большими' файлами,
  понятие небольшой и большой сильно зависит от содержимого файлов.

  Смотрите оригинальный пост Mickael A. Peters, озаглавленный
  "Bootable Utility CD" от 20030409.1816(+0200) и последующие посты:
  http://linuxfromscratch.org/pipermail/blfs-support/2003-April/038817.html

  На моей системе (x86, ext3), размер страниц man перед сжатием был 35564KB.
  Каманда gzip -9 сжала их до размера 20372KB (57.28%), а команда bzip2 
  -9 еще больше до размера 19812KB (55.71%). Т.е. выигрыш в 1.57%. 
  Возможно всякое.
  
  Во внимание не принимается скорость разархивирования. Имеется ли в 
  этом смысл ? Вы получаете быстрый доступ с несжатым страницам man, 
  либо вы получается дополнительноен место за счет небольших накладных 
  расходов по времени. У меня процессор P4-2.5GHz, что даже не 
  позволяет мне заметить эти накладные расходы... :-)

EOT
) | less
}

# С помощью этой функции страница man является уникальной среди всех страниц man,
# заархивированных с помощью  bzip2 и gzip и не заархивированных.
#  $1 директорий, в котором расположен файл
#  $2 имя файла страницы man
# Возвращает 0 (true), если это последняя версия файла и файл нужно сохранить,
# и 1 (false), если файл не является последним (и, следовательно, его можно
# удалить).
function check_unique ()
{
  # NB. Если на этот файл есть жесткая ссылка, то файл и ссылка не 
  # _не_ удаляются. Фактически если есть жесткие ссылки, то у них всех
  # одни и те же знапчения даты/вермени, следовательно их можно удалить 
  # позже.

  # Создание списка всех страниц man с одним и тем же именем
  DIR=$1
  BASENAME=`basename "${2}" .bz2`
  BASENAME=`basename "${BASENAME}" .gz`
  GZ_FILE="$BASENAME".gz
  BZ_FILE="$BASENAME".bz2

  # Поиски и сохранение самой последней страницы
  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

  # В случае, если указанный файл послений, то возвращается 0
  [ "$LATEST" = "$2" ] && return 0
  # Если файл не последний, то возвращается 1
  return 1
}

# Имя скрипта
MY_NAME=`basename $0`

# OK, разбирает аргументы командной строки и инициализируется некоторое 
# состояние, т.е.: не изменяет состояние ссылок, анализирует файл
# /etc/man_db.conf без выдачи каких-либо сообщений, ищет файлman_db.conf в /etc и
# запускает (пере-)сжатие.
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
      ;;
    --automatic)
      COMP_SUF=TBD
      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\" is not an absolute path name"
      exit 1
      ;;
  esac
done

# Перенаправления
case $VERBOSE_LVL in
  0)
     # O, без сообщений
     DEST_FD0=/dev/null
     DEST_FD1=/dev/null
     VERBOSE_OPT=
     ;;
  1)
     # 1, немного сообщений
     DEST_FD0=/dev/stdout
     DEST_FD1=/dev/null
     VERBOSE_OPT=-v
     ;;
  *)
     # 2 наибольшее количество сообщений
     DEST_FD0=/dev/stdout
     DEST_FD1=/dev/stdout
     VERBOSE_OPT="-v -v"
     ;;
esac

# Замечание: на моей машине команда 'man --path' дважды выдает /usr/share/man, один раз 
# с завершающим '/' и один раз - без.
if [ -z "$MAN_DIR" ]; then
  MAN_DIR=`manpath -q -C "$MAN_CONF"/man_db.conf \
            | sed 's/:/\\n/g' \
            | while read foo; do dirname "$foo"/.; done \
            | sort -u \
            | while read bar; do echo -n "$bar "; done`
fi

# Если в ${MAN_CONF}/man_db.conf нет MANDATORY_MANPATH, то также abort 
if [ -z "$MAN_DIR" ]; then
  echo "No directory specified, and no directory found with \`manpath'"
  exit 1
fi

# Проверяем, что указанные директории действительно существуют и их можно читать
for DIR in $MAN_DIR; do
  if [ ! -d "$DIR" -o ! -r "$DIR" ]; then
    echo "Directory '$DIR' does not exist or is not readable"
    exit 1
  fi
done

# Команда Fake?
if [ "$FAKE" != "no" ]; then
  echo "Actual parameters used:"
  echo -n "Compression.......: "
  case $COMP_METHOD in
    --bzip2|--bz2|-b) echo -n "bzip2";;
    --gzip|--gz|-g) echo -n "gzip";;
    --automatic) echo -n "compressing";;
    --decompress|-d) echo -n "decompressing";;
    *) echo -n "unknown";;
  esac
  echo " ($COMP_METHOD)"
  echo "Compression level.: $COMP_LVL"
  echo "Compression suffix: $COMP_SUF"
  echo -n "Force compression.: "
  [ "foo$FORCE_OPT" = "foo-F" ] && echo "yes" || echo "no"
  echo "man_db.conf is....: ${MAN_CONF}/man_db.conf"
  echo -n "Hard-links........: "
  [ "foo$LN_OPT" = "foo-S" ] &&
  echo "convert to soft-links" || echo "leave as is"
  echo -n "Soft-links........: "
  [ "foo$LN_OPT" = "foo-H" ] &&
  echo "convert to hard-links" || echo "leave as is"
  echo "Backup............: $BACKUP"
  echo "Faking (yes!).....: $FAKE"
  echo "Directories.......: $MAN_DIR"
  echo "Verbosity level...: $VERBOSE_LVL"
  exit 0
fi

# Если метод не указан, то печатаем подсказку
if [ -z "${COMP_METHOD}" -a "${BACKUP}" = "no" ]; then
  help
  exit 1
fi

# Если режим резервного копирования, то делаем только резервную копию
if [ "$BACKUP" = "yes" ]; then
  for DIR in $MAN_DIR; do
    cd "${DIR}/.."
    if [ ! -w "`pwd`" ]; then
      echo "Directory '`pwd`' is not writable"
      exit 1
    fi
    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 -cvf "${DIR_NAME}.tar" "${DIR_NAME}" > $DEST_FD1
  done
  exit 0
fi

# Известно, что в MAN_DIR только имена абсолютных путей
# Нужно войти в регистрационную запись локализации man, так что это делается рекурсивно
for DIR in $MAN_DIR; do
  MEM_DIR=`pwd`
  if [ ! -w "$DIR" ]; then
    echo "Directory '$DIR' is not writable"
    exit 1
  fi
  cd "$DIR"
  for FILE in *; do
    # Фиксация случая, когда директорий пустой
    if [ "foo$FILE" = "foo*" ]; then continue; fi

    # Fixes the case when hard-links see their compression scheme change
    # (from not compressed to compressed, or from bz2 to gz, or from gz
    # to bz2)
    # Also fixes the case when multiple version of the page are present,
    # which are either compressed or not.
    if [ ! -L "$FILE" -a ! -e "$FILE" ]; then continue; fi

    # Файлы whatis не сжимаются
    if [ "$FILE" = "whatis" ]; then continue; fi

    if [ -d "$FILE" ]; then
      # Выполняем рекурсивно в этом директории
      echo "-> Entering ${DIR}/${FILE}..." > $DEST_FD0
      # передавать параметр --conf не нужно, посколку указан директорий, с которым работаем
      # но нужно выйти в случае ошибки. Мы должны вернуться в исходный
      # директорий с тем, чтобы $0 выдавался правильно.
      (cd "$MEM_DIR" && eval "$0" ${COMP_METHOD} ${COMP_LVL} ${LN_OPT} \
        ${VERBOSE_OPT} ${FORCE_OPT} "${DIR}/${FILE}") || exit $?
      echo "<- Leaving ${DIR}/${FILE}." > $DEST_FD1

    else # !dir
      if ! check_unique "$DIR" "$FILE"; then continue; fi

      # При автоматическом сжатии получим размер несжатого файла
      # (используются символические ссылки) и выбираем соответсвующий
      # метод сжатия.
      if [ "$COMP_METHOD" = "--automatic" ]; then
        declare -i SIZE
        case "$FILE" in
          *.bz2)
            SIZE=$(bzcat "$FILE" | wc -c) ;;
          *.gz)
            SIZE=$(zcat "$FILE" | wc -c) ;;
          *)
            SIZE=$(wc -c < "$FILE") ;;
        esac
        if (( $SIZE >= (5 * 2**10) )); then
          COMP_SUF=.bz2
        elif (( $SIZE >= (1 * 2**10) )); then
          COMP_SUF=.gz
        else
          COMP_SUF=
        fi
      fi

      # Проверяем, сжпт ли файл с помощью указанного метода
      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

      # Если у нас символическая ссылка
      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
          # Изменяем символическу. ссылку жесткой ссылкой
          rm -f "$FILE" && ln "${LINK}$COMP_SUF" "${FILE}$COMP_SUF"
          chmod --reference "${LINK}$COMP_SUF" "${FILE}$COMP_SUF"
        else
          # сожраняем эту символическую ссылку.
          rm -f "$FILE" && ln -s "${LINK}$COMP_SUF" "${FILE}$COMP_SUF"
        fi
        echo "Relinked $FILE" > $DEST_FD1

      # если у нас обычный файл
      elif [ -f "$FILE" ]; then
        # Будьте аккуратны с жесткими ссылками: создайте список файлов, на которые 
        # есть жесткие ссылки на файлы, которые мы сжимаем или раскрываем.
        # NB. Неоптимально иметь файл, который, в сущности, сжимается 
        # много раз, поскольку у него есть жесткие ссылки. Но это
        # безопасный способ.
        inode=`ls -li "$FILE" | awk '{print $1}'`
        HLINKS=`find . \! -name "$FILE" -inum $inode`

        if [ -n "$HLINKS" ]; then
          # Мы имеем жесткие ссылки! Удалите их теперь.
          for i in $HLINKS; do rm -f "$i"; done
        fi

        # Теперь обрабатываем файл, у которого нет жесткой ссылки
        # Сначала мы выполняем его распаковку, для того, переупаковать с 
        # выбранной степенью сжатия...
        case "$FILE" in
          *.bz2)
            bunzip2 $FILE
            FILE=`basename "$FILE" .bz2`
          ;;
          *.gz)
            gunzip $FILE
            FILE=`basename "$FILE" .gz`
          ;;
        esac

        # Сжимаем файл с выбранной степенью сжатия, если это нужно
        case $COMP_SUF in
          *bz2)
            bzip2 ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}"
            echo "Compressed $FILE" > $DEST_FD1
            ;;
          *gz)
            gzip ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}"
            echo "Compressed $FILE" > $DEST_FD1
            ;;
          *)
            echo "Uncompressed $FILE" > $DEST_FD1
            ;;
        esac

        # Если файл имеет жесткие ссылки, то пересоздаем их (либо жесткие, либо символические)
        if [ -n "$HLINKS" ]; then
          for i in $HLINKS; do
            NEWFILE=`echo "$i" | sed s/\.gz$// | sed s/\.bz2$//`
            if [ "$LN_OPT" = "-S" ]; then
              # Создаем вместе жесткой ссылки символическую
              ln -s "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF"
            else
              # Сохраняем жесткую ссылку как жесткую
              ln "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF"
            fi
            # Работает в действительность только для жестких ссылок. 
            # С символическими ссылками ничего не происходит
            chmod 644 "${NEWFILE}$COMP_SUF"
          done
        fi

      else
        # Есть проблема, если это тне символическая и не обычный
        # файл. Очевидно, что сюда мы никогда не попадем... :-(
        echo -n "Whaooo... \"${DIR}/${FILE}\" is neither a symlink "
        echo "nor a plain file. Please check:"
        ls -l "${DIR}/${FILE}"
        exit 1
      fi
    fi
  done # for FILE
done # for DIR

EOF

В роли пользователя root сделайте файл compressdoc исполняемым для всех пользователей:

chmod -v 755 /usr/sbin/compressdoc

Теперь, чтобы сжать все ваши системные файлы man, вы можете перейти в роль пользователя root, и выполнить команду compressdoc --bz2. Чтобы получить исчерпывающую подсказку о том, что может делать этот скрипт, вы также можете запустить команду compressdoc --help.

Не забудьте, что некоторые программы, такие как система X Window и XEmacs также устанавливают свою документацию в нестандартных местах (например, в /usr/X11R6/man и т.д.). Убедитесь, что вы добавили места в файл /etc/man_db.conf в виде строк вида MANDATORY_MANPATH </path>.

Пример:

    ...
    MANDATORY_MANPATH                       /usr/share/man
    MANDATORY_MANPATH                       /usr/X11R6/man
    MANDATORY_MANPATH                       /usr/local/man
    MANDATORY_MANPATH                       /opt/qt/doc/man
    ...

Как правило, в системах установки пакетов страницы man/info не сжимаются, что значит, что вы должны запустить скрипт еще раз, если вы хотите, чтобы размер вашей документации был минимальным. Также, обратите внимание, что можно без проблем запускать скрипт после обновления пакета; если у вас есть несколько версий страницы (например, одна сжата и одна несжата), то самая последняя страница будет сохранена, а другие будут удалены.

Перевод сделан с варианта оригинала, датированного 2008-04-21 23:27:43 +0000


Предыдущий раздел: Оглавление Следующий раздел:
Генерация случайных чисел   Глава 4. Безопасность