shell-framework

Материал из Xgu.ru

Перейти к: навигация, поиск
Автор: Рома Слєпчик

shell-framework - framework для упрощения написания shell скриптов, а именно такие стандартные решения как help, параметры, конфигурационные файлы. Автором данного фреймворка является Nick Shevelev / Николай Шевелев известный также как Beggy.

Содержание

[править] Установка в Debian/Ubuntu

Установите пакет apt-transport-https из репозитория.

добавьте в /etc/apt/sources.list строки

deb https://svn.origo.ethz.ch/shell-framework/repositories/debian unstable main
deb-src https://svn.origo.ethz.ch/shell-framework/repositories/debian unstable main

добавляем ключ

wget --no-check-certificate https://svn.origo.ethz.ch/shell-framework/repositories/debian/beggyKey.txt -O - | apt-key add -

устанавливаем

aptitude update
aptitude install shell-framework

[править] Удаление в Debian/Ubuntu

удаляем стандартным решением

aptitude purge shell-framework

удаляем ключ

apt-key del BeggyCode@gmail.com

чистим /etc/apt/sources.list от ненужных строк

[править] Основные концепции

  • Параметры. CLI программа должна уметь работать с параметрами. Параметры могут быть короткими (-M) и длинными(--multi-volume) . Первые нужны непосредственно для ввода их в командной строке и должны быть краткими для скорости ввода, вторые предназначены для использования программы в других скриптах и потому должны быть минимально читаемыми.
  • Ожидаемые параметры и поведение. На самом деле я знаю лишь один by default параметр - "-h" и его длинный синоним "--help". Скрипт, будучи запущен с таким параметром, должен распечатать минимальную справку о себе и своих параметрах и закончить выполнение.
  • Наличие конфигурационных файлов. Конечно, это не обязательно, но, иногда, крайне желательно, в особенности для скриптов с дюжиной и более возможных параметров.

[править] Пример использования

вот так выглядит обычный скрипт с параметрами

#!/bin/bash

function printHelp () {
    cat - << END_OF_HELP
It is test script which just print Hello, <name>.
Usage $0 [parameter] ...
Paramter:
    -n <name> - define the <name>. default value is "World"
    -h        - print the help and exit from script
END_OF_HELP
}

declare name="World"

while getopts ":n:h" Option
do
  case $Option in
    n ) name="${OPTARG}" ;;
    h ) printHelp ; exit 1 ;;
  esac
done

echo "Hello, ${name}!"

Тот же скрипт, только с использованием набора библиотек shell-framework

#!/bin/bash

shF_PATH_TO_LIB="./shell-framework/lib"
source "${shF_PATH_TO_LIB}/base"

setDescription "Hello world is example script."

#addOption <name> [defaultValue] [shortForm] [longForm] [type] [shortDescription] [longDescription] [priority] [notForConfig]]
#   type can be shF_SIMPLE_OPTION or shF_OPTION_WITH_VALUE
addOption "name" "World" "-n" "--name" "${shF_OPTION_WITH_VALUE}" "you can define your name as ${shF_COMMON_PARAMETER_NAME}." "" "110"


if ! initConfig "$@"  ; then
    exit 1
fi

echo "Hello, ${name}!"

[править] Подробнее

shF_PATH_TO_LIB="./shell-framework/lib"
source "${shF_PATH_TO_LIB}/base"

shF_PATH_TO_LIB определяет, где находится библиотека. Нужно обязательно правильно проинициализировать эту переменную, потому что ее используют все библиотечные скрипты, чтобы подгружать друг-друга. Строка с source подключает файл base, который по сути является набором стандартных подключений - чтобы не писать каждый раз "подключить библиотеку help, config и тд".

setDescription "Hello world is example script."

Определяет краткое описание нашего скрипта. Оно будет использовано потом при показе help-а

#addOption <name> [defaultValue] [shortForm] [longForm] [type] [shortDescription] [longDescription] [priority] [notForConfig]]
#   type can be shF_SIMPLE_OPTION or shF_OPTION_WITH_VALUE

Небольшая подсказка по параметрам.

addOption "name" "World" "-n" "--name" "${shF_OPTION_WITH_VALUE}" "you can define your name as ${shF_COMMON_PARAMETER_NAME}." "" "110"

Добавляет новый параметр(option) со следующими атрибутами:

  • переменная name, которая будет хранить его значение
  • значение по умолчанию: World
  • краткая форма -n
  • длинная --name
  • после него ожидается значение (${shF_OPTION_WITH_VALUE})
  • описание: "you can define your name as ${shF_COMMON_PARAMETER_NAME}."
  • При распечатке в help-е список параметров будет отсортирован в соответствии с весом заданным при инициализации - 110.
if ! initConfig "$@"  ; then
    exit 1
fi

initConfig "$@" пытается "распарсить" строку параметров в соответствии с конфигурацией.

[править] Результат выполнения скрипта

$ ./helloWorld.sh
Hello, World!
$ ./helloWorld.sh -n Nick
Hello, Nick!
$ ./helloWorld.sh --name Nick
<current time="">: ERROR ./shell-framework/lib/opts.parseOpts:122 The value for option (--name) must be defined.

Как видите последний скрипт запустился с ошибкой. Дело в том, что стандарта на то, как должны быть оформлены параметры и значения нет и автор предпочел следующий подход. Короткие параметры отделяются от значений пробельными символами, а длинные символом "="

$ ./helloWorld.sh --name=Nick
Hello, Nick!

пример запуска с параметром help

$ ./helloWorld.sh -h 
Hello world is example script.
Usage: ./helloWorld.sh [option(s)] [command]
Options:
        -h|--help       print this help
        --help-options  print detailed description of options using
        -l <parameter>|--shF_logLevel=<parameter>   define the current log level (<parameter>). You can use the following
           number - 0(shF_EVERYTHING), 1(shF_DEBUG), 2(shF_INFO), 3(shF_HIGH), 4(shF_WARN), 5(shF_ERROR). Config name is
           shF_currentLogLevel. Default value is "2".
        --logFile=<parameter>     define the <parameter> as log stream. You can use stdError, stdOut or file name. Config name
           is shF_currentLogFile. Default value is "stdError".
        -c <parameter>|--config=<parameter> define the <parameter> as property file which will be loaded.
        -p|--print-config       print the current configuration.
        -n <parameter>|--name=<parameter>   you can define your name as <parameter>. Config name is name. Default value is "World"

Как видите сгенерировался не только help, но и множество дополнительных параметров(опций) - уровень логгинга, использование лог файла, поддержка конфигурационных файлов. Если вам нужен только help поменяйте в строке source ${shF_PATH_TO_LIB}/base base на help

[править] Конфигурационные файлы

Когда мы создаем параметр, то мы задаем так же и имя переменной, которая будет проинициализирована значением этого параметра. Порядок инициализации переменной будет следующим:

  • значение по умолчанию, если оно есть
  • значение из конфигурационного файла(далее "конфиг"), если оно есть
  • значение командной строки, если оно есть

Так что если мы создадим файл config.txt с таким содержимым

name="Config"

и запустим наш скрипт то получим следующее

$ ./helloWorld.sh --config=./config.txt
Hello, Config!

Ещё одна очень полезная фишка это самостоятельная генерация конфигурационных файлов

$ ./helloWorld.sh -p > config.txt
$ cat config.txt
#define the current log level (). You can use the following number - 0(shF_EVERYTHING), 1(shF_DEBUG), 2(shF_INFO),
3(shF_HIGH), 4(shF_WARN), 5(shF_ERROR). Default value is "2".
#shF_currentLogLevel="2"

#define the  as log stream. You can use stdError, stdOut or file name. Default value is "stdError".
#shF_currentLogFile="stdError"

#you can define your name as . Default value is "World".
#name="World"

Скрипт генерирует конфиг с комментариями перед каждой переменной (они начинаются со знака #), которые вы можете сами определить при создании нового параметра. Как вы видите, все строки в этом config файле закомментированы - это произошло потому, что ни одна из переменных не отличалась на момент генерации конфига от своего значения по умолчанию. Можно определить параметры и в этом случае конфигурация будет несколько иной:

$ ./helloWorld.sh -p -n zysyl
#define the current log level (). You can use the following number - 0(shF_EVERYTHING), 1(shF_DEBUG), 2(shF_INFO), 
3(shF_HIGH), 4(shF_WARN), 5(shF_ERROR). Default value is "2".
#shF_currentLogLevel="2"

#define the  as log stream. You can use stdError, stdOut or file name. Default value is "stdError".
#shF_currentLogFile="stdError"

#you can define your name as . Default value is "World".
name="zysyl"

Таким образом, вы можете записать текущие настройки в файл и использовать их в будущем.

[править] Добавляем новый параметр

Предположим мы хотим добавить новый параметр к нашему скрипту. Для этого добавляется всего 1-на строка с параметрами в скрипт

#!/bin/bash

shF_PATH_TO_LIB="./shell-framework/lib"
source "${shF_PATH_TO_LIB}/base"

setDescription "Hello world is example script."

#addOption <name> [defaultValue] [shortForm] [longForm] [type] [shortDescription] [longDescription] [priority] [notForConfig]]
#   type can be shF_SIMPLE_OPTION or shF_OPTION_WITH_VALUE
addOption "name" "World" "-n" "--name" "${shF_OPTION_WITH_VALUE}" "you can define your name as ${shF_COMMON_PARAMETER_NAME}." 
"" "110"
addOption "greeting" "Hello" "-b" "--bye" "${shF_OPTION_WITH_VALUE}" "you can define greeting word as ${shF_COMMON_PARAMETER_NAME}." "" "120"


if ! initConfig "$@"  ; then
        exit 1
    fi

echo "${greeting}, ${name}!"

пример запуска

$ ./helloWorld.sh -b "That's all" -n "folks"
That's all, folks!

Эта библиотека не ограничивается работой с параметрами коммандной строки, конфигурационными файлами и автоматической генерации описания вашего скрипта. В ней так же есть ассоциативные массивы (их не было в bash до версии 4), некоторое расширение работы с trap и unit тестирование. Конечно же у неё есть и недостатки - например скорость работы или усложнение чтения кода для непросвещённых.

[править] Дополнительная информация