Translate

четвер, 15 серпня 2013 р.

Dialog: ncurses-інтерфейс до shell-скрипта

Мабуть багато-хто якось думав, що було б непогано наділити власний скрипт графічним інтерфейсом. Навіщо він потрібен - це вже інше питання: наприклад, для людей, далеких від консольних програм, користування псевдографічним інтерфейсом буде зрозумілішим чи просто таким чином скрипт буде виглядати дещо професійніше або ж ви лише думаєте, що він необхідний - а насправді це просто марнування часу. Для реалізації таких простих інтерфейсів будемо використовувати програму dialog (ncurses-інтерфейс) та shell.

Звісно програму необхідно спочатку встановити:

# aptitude install dialog

Продемонструю його роботу з найпростішим case-скриптом.

#!/bin/bash

dialog --title 'Перезапуск мережі' \
       --yesno "Ви насправді бажаєте перезавантажити сервіс мережі на комп'ютері?" 10 40

case "$?" in
'0')
sudo service networking restart > /dev/null &2>1
echo 'Restarting...'
;;
'1')
exit 0
;;
-1|255)
echo "Сталась помилка, або ви натиснули ESC"
esac

Ключем "-yesno" вказуємо програмі dialog створити вікно з вибором "Так" чи "Ні", "--title" - встановлює назву вікна. Відповідь, що була обрана буде ідентифікуватись зі змінної $? (код завершення останньої команди). Тобто dialog буде повертати "0", якщо було обрано "Yes" та "1" - якщо "No". "10 40" - це позиція вікна, можна указати дефолтні - "0 0".
Також dialog повертає код "-1" у випадку, коли сталась помилка та "255", якщо було натиснено клавішу ESC.



У наступному прикладі буде продемонстровано вивід вікна, де користувач може самостійно ввести програму, що хоче запустити:

#!/bin/bash

TMPFFCMD="/tmp/cmd.tmp"
dialog --title 'Execute command' --inputbox 'Уведіть програму, яку хочете запустити:' 10 40 'ls' 2> $TMPFFCMD
CMD2RUN=$(cat $TMPFFCMD)

if [ "$?" -ne "-1" ]; then
$CMD2RUN
else
echo "Отримано код -1 від dialog"
fi

rm -f $TMPFFCMD

Параметр "--inputbox" призводить до появи вікна введення, де 'ls' буде вказана, як дефолтна програма. Вибір програми через stderr буде перенаправлено в змінну $TMPFFCMD. У випадку появи помилки буде виведено відповідне повідомлення.



Тепер створимо діалогове меню вибору програм на ncurses:

#!/bin/bash
TMPFCMD="/tmp/cmd.tmp"

dialog --title 'Execute command' --menu 'Оберіть програму для запуску' 0 0 0 \
l 'ls -la' \
p pwd \
d date \
u 'uname -a' \
w whoami 2> $TMPFCMD
CMD2RUN=$(cat $TMPFCMD)

if [ "$?" -eq "0" ]; then
case "$CMD2RUN" in
"l")
ls -la
;;
"p")
pwd
;;
"d")
date
;;
"u")
uname -a
;;
"w")
whoami
;;
esac
fi

rm -f $TMPFCMD

Кожна програма супроводжується тегом в меню dialog, котрий буде записуватись в $TMPFCMD після вибору відповідного пункту в меню. Власне від записаного тегу і буде залежати яку програму буде запущено.



Останній тип діалогових вікон не запитує в користувача жодних данних, а лиш надає певну інформацію користувачу. Їх роботу продемонструємо на такому прикладі:

#!/bin/bash

dialog --title 'Infoboxes script' --infobox "Цей скрипт не виконує жодної корисної роботи, він просто демонструє роботу інформаційних діалогових вікон" 10 50

sleep 2

{
i=0
while [ "$i" -lt "110" ]; do
sleep 0.25
echo $i
let "i += 10"
done; sleep 1; } | dialog --title 'Infoboxes script' --gauge 'Перебіг процесу' 10 50 0

dialog --title 'Infoboxes script' --infobox 'Скоро скрипт завершиться...' 10 50

sleep 2

dialog --title 'Infoboxes script' --msgbox 'Будь ласка, натисніть OK' 10 50
dialog --title 'Infoboxes script' --pause 'Пауза' 10 50 5

Спершу виводиться діалогове інформаційне вікно (опція "--infobox"), надалі - смуга завантаження ("--gauge") та пауза ("--pause"). Зауважу що для відображення рівня завантаження необхідно передавати (через пайп, як в скрипті вище) dialog-у число рівня завантаження.



Накінець розглянемо комплексний скрипт з використанням всіх вищезгаданих моживостей утиліти dialog. Створимо файл /tmp/conf.txt з таким змістом:

port:3322
threads:2
logdir:/opt/user6/logs/
confdir:/opt/user6/etc/

Скрипт матиме можливість редагувати значення цього файлу за допомогою awk і буде виглядати так:

#!/bin/sh
#автор http://unstableme.blogspot.com/

#Розміщення файлу, що буде редагуватись та опис тимчасових файлів для вікон dialog.

file=/tmp/conf.txt
tempfile1=/tmp/dialog_1_$$
tempfile2=/tmp/dialog_2_$$
tempfile3=/tmp/dialog_3_$$

#Перехоплення системних викликів. Видалення тимчасових файлів у разі надсилання процесу відповідних сигналів.
trap "rm -f $tempfile1 $tempfile2 $tempfile3" 0 1 2 5 15

#Опис функції _edit()
_edit () {
   items=$(awk -F\: '{print $1,$2}' $file)
   #Вивід меню із пропозицією редагування відповідних файлу conf.txt.    
   dialog --title "A Sample Application" \
          --menu "What you want to change :" 0 0 0 $items 2> $tempfile1

   retval=$?
   parameter=$(cat $tempfile1)

   #Якщо код виконання останньої команди рівний 0 - присвоїти значення змінної $parameter змінній $tochange. Інакше - поповернути 1.
   [ $retval -eq 0 ] && tochange=$parameter || return 1
   
   # awk виводить значення другого стовпчика, якщо значення першого рівне x(змінна tochange).    
   val=$(awk -F\: -v x=$tochange '$1==x {print $2}' $file)
   echo $val > tmp.log
   
   #Діалог зміни необхідного параметру файлу conf.txt
   dialog --clear --title "Inputbox - Test" \
          --inputbox "Enter new value($tochange)" 0 0 $val 2> $tempfile2
   
   #Діалог,  що запитує чи наспраді ми хочемо змінити значення    dialog --title "Confirmation"  --yesno "Commit ?" 0 0
   
    case $? in
       0) newval=$(cat $tempfile2)
          # awk змінює значення на n($newval) у разі якщо значення у першому стовпчику буде рівне x($tochange)
          awk -v x=$tochange -v n=$newval '
               BEGIN {FS=OFS=":"}$1==x {$2=n} {print}
               ' $file > $file.tmp
          mv $file.tmp $file
       ;;
       1|255) dialog --infobox "No Changes done" 0 0
              sleep 2
   ;;
   esac
   dialog --textbox $file 0 0
}
 # Функція виведення першого основного вікна з пунктами меню
 _main () {   dialog --title "A sample application" \
           --menu "Please choose an option:" 15 55 5 \
                   1 "View the config file" \
                   2 "Edit config file" \
                   3 "Exit from this menu" 2> $tempfile3

   retv=$?
   choice=$(cat $tempfile3)

   #Аналізується код повернення команди dialog: якщо код виконання останньої команди 1 чи 255(клавіша ESC) - вихід
   [ $retv -eq 1 -o $retv -eq 255 ] && exit

  #Запуск вищеописаних функцій залежно від вибору    
  case $choice in
       1) dialog --textbox $file 0 0
          _main
           ;;
       2) _edit
          _main ;;
       3) exit ;;
   esac

}
#Скрипт стартує з запуску функції _main
_main 


Як помітно  з коментарів до коду, на виході буде отримано новий файл зі зміненим значенням навпроти необхідного параметру. Якщо маєте питання чи просто помітили помилку - ласкаво прошу в коментарі.

Посилання: 
http://www.unixcl.com/2009/12/linux-dialog-utility-short-tutorial.html
http://www.ibm.com/developerworks/ru/library/l-dialog/
http://www.ibm.com/developerworks/ru/library/l-awk1/
http://www.thegeekstuff.com/2010/01/8-powerful-awk-built-in-variables-fs-ofs-rs-ors-nr-nf-filename-fnr/

Немає коментарів:

Дописати коментар