Псевдографика в консоли Unix/Linux. Немного больше User Friendly чем вы могли себе позволить

21:57

Привет! Бывает, хочется забыть о «скучной» консоли, разбавить ее хоть капелькой интерактива, особенно если часто приходиться делать одни и теже операции и тем более если вы пишите для облегчения своей участи скрипты. Итак, псевдографика. За мной читатель, я покажу тебе такую консоль!


Наверняка многие задумывались, запуская make && make install во FreeBSD или apt-get install, например в Debian, как же хорошо было бы использовать подобные диалоги конфигурирования. Они неоправданно забыты и практически вообще не используются в пользовательских скриптах. Очень и очень зря.

Исправить это может замечательная утилита dialog.
Она присутствует во FreeBSD седьмой, восьмой ветки, а в Debian, например, можно сделать apt-get install dialog. Вообще-то, это разные программы.
Во FreeBSD немного попроще версия:

$ dialog

dialog version 0.3, by Savio Lam (lam836@cs.cuhk.hk).
  patched to version 0.4 by Stuart Herbert (S.Herbert@shef.ac.uk)
  Changes Copyright © 1995 by Andrey A. Chernov, Moscow, Russia
  patched by Anatoly A. Orehovsky (tolik@mpeks.tomsk.su)

* Display dialog boxes from shell scripts *

Usage: dialog --clear
       dialog --create-rc <file>
       dialog [--title <title>] [--clear] [--hline <line>] [--hfile <file>]\
              <Box options>

Box options:

  --yesno     <text> <height> <width> [yes|no]
  --msgbox    <text> <height> <width>
  --prgbox    "<command line>" <height> <width>
  --infobox   <text> <height> <width>
  --inputbox  <text> <height> <width> [<init string>]
  --textbox   <file> <height> <width>
  --menu      <text> <height> <width> <menu height> <tag1> <item1>...
  --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...
  --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...
  --ftree     <file> <FS> <text> <height> <width> <menu height>
  --tree      <FS> <text> <height> <width> <menu height> <item1>...


В Linux-версии возможностей побольше:

$ dialog
cdialog (ComeOn Dialog!) version 1.1-20080316
Copyright 2000-2006,2007 Thomas E. Dickey
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

* Display dialog boxes from shell scripts *

Usage: dialog <options> { --and-widget <options> }
where options are "common" options, followed by "box" options

Special options:
  [--create-rc "file"]
Common options:
  [--ascii-lines] [--aspect <ratio>] [--backtitle <backtitle>]
  [--begin <y> <x>] [--cancel-label <str>] [--clear] [--colors]
  [--cr-wrap] [--default-item <str>] [--defaultno] [--exit-label <str>]
  [--extra-button] [--extra-label <str>] [--help-button]
  [--help-label <str>] [--help-status] [--ignore] [--input-fd <fd>]
  [--insecure] [--item-help] [--keep-tite] [--keep-window]
  [--max-input <n>] [--no-cancel] [--no-collapse] [--no-kill]
  [--no-label <str>] [--no-lines] [--no-ok] [--no-shadow] [--nook]
  [--ok-label <str>] [--output-fd <fd>] [--print-maxsize] [--print-size]
  [--print-version] [--separate-output] [--separate-widget <str>]
  [--shadow] [--single-quoted] [--size-err] [--sleep <secs>] [--stderr]
  [--stdout] [--tab-correct] [--tab-len <n>] [--timeout <secs>]
  [--title <title>] [--trace <file>] [--trim] [--version] [--visit-items]
  [--yes-label <str>]
Box options:
  --calendar     <text> <height> <width> <day> <month> <year>
  --checklist    <text> <height> <width> <list height> <tag1> <item1> <status1>...
  --dselect      <directory> <height> <width>
  --editbox      <file> <height> <width>
  --form         <text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1>...
  --fselect      <filepath> <height> <width>
  --gauge        <text> <height> <width> [<percent>]
  --infobox      <text> <height> <width>
  --inputbox     <text> <height> <width> [<init>]
  --inputmenu    <text> <height> <width> <menu height> <tag1> <item1>...
  --menu         <text> <height> <width> <menu height> <tag1> <item1>...
  --mixedform    <text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1> <itype>...
  --mixedgauge   <text> <height> <width> <percent> <tag1> <item1>...
  --msgbox       <text> <height> <width>
  --passwordbox  <text> <height> <width> [<init>]
  --passwordform <text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1>...
  --pause        <text> <height> <width> <seconds>
  --progressbox  <height> <width>
  --radiolist    <text> <height> <width> <list height> <tag1> <item1> <status1>...
  --tailbox      <file> <height> <width>
  --tailboxbg    <file> <height> <width>
  --textbox      <file> <height> <width>
  --timebox      <text> <height> <width> <hour> <minute> <second>
  --yesno        <text> <height> <width>



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

cat ./xbackup.sh
#!/bin/sh

SRC="/usr/home/dev/"
    SITE="${SRC}_Web/"
    PROJECT="${SRC}_Project/"

# куда будем складывать бэкапы
DST="/usr/home/share/BACKUP/"

# реквизиты для Mysql
SQLLOGIN="root"
SQLPASS="TopSecretPassword"
SQLHOST="localhost"

/* --------------------------------------------------------------------------------------------------------- */
# именовать файлы дампов и архивов будем по дате
DATE=`date "+%Y.%m.%d_%H-%M-%S"`
DSRC=""
# переменная для сохранения выбранного типа бэкапа (база или сайт)
backupType=0

# вызываемая программа для создания диалога
DIALOG=dialog
# временный файл
tempfile=`mktemp /tmp/bkp.XXXXXX`
trap "rm -f $tempfile" 0 1 2 5 15

# функция для вывода информационного окна
InfoDialog() {
    ${DIALOG} --msgbox "$1" 5 70
}

# упаковка файлов из выбранной директории
BackupFiles() {
    if [ ! -d ${2} ]then
        
mkdir -p ${2}
    fi
    
tar -c --gzip -f "${2}${DATE}.tar.gz" "${1}"
    InfoDialog "OK -> ${2}${DATE}.tar.gz"
}

# сохранения дампа базы в файл
BackupMySQL() {
    case ${1} in
        "All_Database")
            mysqldump -R -E --triggers -u"${SQLLOGIN}" -p"${SQLPASS}" --all-databases > "${tempfile}"
            ;;
        "")
            InfoDialog "Backup has been canceled"
            exit
            ;;
        *)
            mysqldump -R -E --triggers -u"${SQLLOGIN}" -p"${SQLPASS}" ${DBase} > "${tempfile}"
            ;;
    esac
    
cp "${tempfile}" "${DST}${1}-${DATE}.sql"
    # компрессия gzip, отключено за ненадобностью — распаковывать неудобно
    echo tar -c --gzip -f "${2}${DATE}.dump" "${tempfile}"
    InfoDialog "OK -> ${2}${DATE}.dump"
}

# выбор базы данных из списка существующих на сервере
ChooseDatabase() {
    # получаем листинг баз
    DBases=` echo "SHOW DATABASES" | mysql -u"${SQLLOGIN}" -p"${SQLPASS}" `
    # хитро обеспечиваем опцию All_Database
    List="All_${DBases}"
    # выводим диалог выбора базы из списка
    $DIALOG  --title "Please choose a Database " --tree "FS" "List of existing databases" 14 78 7 ${List} 2> ${tempfile}

    case $? in
    0)
        # выбор сделан
        DBase=`cat ${tempfile}`
        BackupMySQL ${DBase}
        ;;
    1|255)
        # диалог прерван (ескейп например)
        InfoDialog "Backup has been canceled"
        exit
        ;;
    esac
}

# выбор папки с сайтом (реализованвыбор нужного  из денвероподобной структуры папок с сайтами)
ChooseDomain() {
    Paths=`ls ${1}`
    List=""
    isEmpty=true
    
for dName in ${Paths}
    do
        # выводим только папки внутри которых есть корен сайта или поддомен www (структура реализована совсем как в денвере)
        if [ -d "${1}${dName}/www" ] || [ -d "${1}${dName}/htdocs" ]then
            
List="${List} ${dName}"
            isEmpty=false
        
fi
    done


    # таким образом проверяем что выбран корень сайта и пора всетаки паковать его, иначе выводим список подпапок
    if ${isEmpty}then
        
Count=`echo ${SRC} | wc -c | tr -d ' '`
        DSRC=`echo ${1} | awk "{ print substr($ 1, ${Count}) }"`
        return 0;
    fi

    # собстно вывод список папок внутри выбранной
    $DIALOG  --title "Please choose a path " --tree "FS" "List of existing domains" 14 78 7 ${List} 2> ${tempfile}

    case $? in
    0)
        DName=`cat ${tempfile}`
        ChooseDomain "${1}${DName}/"
        ;;
    1|255)
        InfoDialog "Backup has been canceled"
        exit
        ;;
    esac

}

ProcessBackup() {
    case $1 in
        Site)
             ChooseDomain ${SITE}
             BackupFiles "${SRC}${DSRC}" "${DST}${DSRC}"
            ;;
        MySQL)
            ChooseDatabase
            ;;
        *)
            ;;
    esac
}

TypeDialog() {
    ${DIALOG} --title "Choose backup type:" --menu "This is backup types" 12 50 4 \
                                            "Site" "backup web-site" \
                                            "MySQL" "Mysql database" 2> ${tempfile}

    case $? in
    0)
        ProcessBackup `cat ${tempfile}`
        TypeDialog
        ;;
    1|255)
        InfoDialog "Backup has been canceled"
        exit
        ;;
    esac

}

TypeDialog

 



Выглядит это вот так:
Основное меню
Выбор сайта для бэкпап
Выбор базы для бэкапа
База успечно сдампилась


Вот и все. Теперь при работе скрипта можно любоваться интерактивными «окошечками». Таким же образом легко реализовать выполнение любых консольных команд, а сочетая это с запуском putty из командной строки с авторизацией по ключу, можно дать красивый консольный интерфейс для, например, рестарта апачи на дев-сервере(конечно через sudo с жесткими ограничениями), всем разработчикам в команде, даже незнакомым с *nix системами.
Уверен, кому-то изложенные знания пригодятся для того чтобы сделать консоль своего сервера «более User Friendly».

P.S. В процессе написания наткнулся на хорошие примеры http://www.oszone.net/2833/, кое-что оттуда сразу внедрил.

(c)