Утилита dialog для использования диалоговых окон в shell-скриптах

Утилита dialog – одна из немногих, помогающих создавать дружелюбные к пользователю (в плане пользовательского интерфейса) скрипты и программы. Она может конструировать различные диалоговые окна, не нуждаясь при этом в запущенном графическом интерфейсе – достаточно лишь консоли, ведь для рисования используется библиотека ncurses. Как следствие, dialog хорошо приспособлен для использования в shell-скриптах, в них он и применяется в большинстве случаев. Основная документация по утилите сосредоточена в man-странице (man dialog). Также стоит посетить сайт проекта: http://hightek.org/dialog/.

Стоит отметить, что существуют аналоги dialog'а, специально рассчитанные на использование в графическом окружении – универсальный Xdialog (относительно совместим с dialog), gtkdialog (окна рисуются при помощи графической библиотеки GTK), kdialog (для работы в KDE) и zenity (предназначен для использования вместе с Gnome). Стоит отметить, что, по крайней мере, Xdialog, помимо стандартных диалоговых окон из dialog'а, имеет еще и немного своих: древовидные списки, поле для редактирования многострочных текстовых данных и т.п.

Вот краткий список диалоговых окон, которые способен рисовать dialog:

История dialog

К сожалению, история этой утилиты затеряна в прошлом веке. Первое упоминание о dialog'е встречается в README-файле, поставляющемся с исходными кодами утилиты, и датируется 15 января 1996 года. Доподлинно известно, что на данный момент автором утилиты dialog является Томас Дикей (Thomas E. Dickey).


Примеры использования

Для начала реализуем простейшее диалоговое окно, спрашивающее нас о том, хотим ли мы выключить компьютер или нет. Если мы отвечаем "Да", у нас запрашивается пароль текущего пользователя и компьютер завершается; иначе компьютер остается в рабочем состоянии. Вот исходный код соответствующего shell-скрипта:

#!/bin/bash

dialog --title 'Выключить компьютер' 
       --yesno 'Вы действительно хотите выключить компьютер?' 10 40

case "$?" in
	'0')
	sudo poweroff
	;;
	'1')
	exit
	;;
	'-1')
	echo 'Вы вышли, нажав ESC, или же внутри dialogа произошла ошибка'
	exit 1
	;;
esac

Разберем его работу. Вначале мы устанавливаем соответствующий заголовок для диалогового окна. Этот заголовок будет отображаться на экране в "шапке" диалогового окна независимо от типа отображаемого диалогового окна. Далее, следующим параметром мы выбираем необходимый нам тип диалогового окна – окно с кнопками "Да\Нет". Полный список опций с соответствующими им вариантами диалоговых окон можно найти в man-странице утилиты. Далее, в двух последних параметрах мы указываем высоту и ширину окна.

Результат нажатия на ту или иную кнопку в диалоговом окне возвращается в переменной "$?": 0 – если мы нажали на "Yes" или "OK", "1" – если мы нажали на "No" или "Cancel" и "-1" – если мы вышли из диалогового окна по нажатию Esc или внутри самой утилиты произошла некая программная ошибка. Подробнее об этих кодах возврата можно прочитать опять-таки в man-странице утилиты dialog.

Примерно по такой схеме и строится вся работа с dialog'ом. Иногда вместо (или вместе с) кода возврата возвращается еще и некоторое введенное пользователем значение – оно выводится в STDERR, но можно настроить и вывод его в STDOUT. Примером подобного поведения может служить "поле ввода" – inputbox. Следует заметить, что на стандартный вывод передается различная управляющая информация, отвечающая за прорисовку элементов на экране – как следствие, при перенаправлении STDOUT куда-нибудь в файл мы не увидим на экране никаких диалоговых окон.

В качестве примера работы с возвращаемым значением напишем скрипт, получающий имя команды оболочки через поле ввода и запускающий эту команду:

#!/bin/bash

TMPFFCMD="/tmp/cmd.tmp"
dialog --title 'Execute command' 
       --inputbox 'Enter command to execute:' 10 40 'ls -la' 2> $TMPFFCMD
CMD2RUN=$(cat $TMPFFCMD)

if [ "$?" -ne "-1" ]; then
	$CMD2RUN
else
	echo "Get -1 return code from dialog"
fi

rm -f $TMPFFCMD

В STDERR может возвращаться не только введенное пользователем значение, но и результат выбора им какого-либо пункта меню, радиокнопки и т.п. Вот соответствующий пример использования:

#!/bin/bash

TMPFCMD="/tmp/cmd.tmp"

dialog --title 'Execute command' 
       --menu 'Choose command to execute' 50 40 40 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

Для меню и радиокнопок каждый пункт в списке элементов предваряется тегом, который выводится в STDERR при выборе соответствующего пункта меню. При нажатии на клавишу, соответствующую первой букве тега, происходит переход на соответствующий пункт в меню – это своего рода аналог традиционных "горячих клавиш".

Последний тип используемых диалоговых окон ничего не запрашивает у пользователя и, как следствие, ничего не возвращает. Он лишь выводит информацию о каком-нибудь процессе для пользователя. В качестве примера можно привести информационное окно – параметр командной строки infobox и полосу загрузки (gauge). Приведу исходный код скрипта, который лишь иллюстрирует работу рассмотренных диалоговых окон и не выполняет совсем никакой полезной работы:

#!/bin/bash

dialog --title 'infoboxes.sh' --infobox "Этот скрипт не выполняет никакой \
полезной работы – он просто демонстрирует работу различных информационных \
диалоговых окон" 10 50

sleep 2

{
	i=0
	while [ "$i" -lt "100" ]; do
	sleep 0.25
	echo $i
	let "i += 10"
done; echo '100'; sleep 1; } | dialog --title 'infoboxes.sh' --gauge 'Gauge' 10 50 0

dialog --title 'infoboxes.sh' --infobox 'Infobox' 10 50

sleep 2

dialog --title 'infoboxes.sh' --msgbox 'Msgbox -- please press OK' 10 50
dialog --title 'infoboxes.sh' --pause 'Pause' 10 50 5
dialog --title 'infoboxes.sh -- tailbox' --tailbox $0 10 50

Диалоговое окно 'tailbox' можно применять для вывода на экран содержимого изменяющегося файла, например какого-либо системного журнала. Действия, производимые этим элементом, аналогичны тому, что делает команда tail -f, разве что обернуты в красивую ncurses-оболочку. В нашем скрипте мы при помощи tailbox'а выводим код этого же скрипта на экран (а точнее то, что поместилось в окошко 50x10).

Отдельно следует рассмотреть диалоговое окно 'gauge'. Число, указываемое последним параметром, является начальным значением, выводимым в полосе загрузки. Чтобы менять это значение в ходе работы какой-либо программы, следует подавать на стандартный вход dialog'а числа, соответствующие той величине, которую мы хотим видеть в полосе прокрутки. При этом стоит отметить, что если вы подадите на стандартный вход число 120, то dialog, недолго раздумывая, отобразит в полосе загрузки 120%, а не 100%, как можно было бы ожидать.

В нашем примере числа, вызывающие приращение полосы загрузки, формируются в отдельном блоке кода с шагом 10, соответственно через каждые 250 миллисекунд dialog увеличивает процентное значение полосы загрузки на 10%. По достижении 100% мы делаем паузу, чтобы пользователь заметил полученное стопроцентное значение, иначе скрипт сразу уйдет на выполнение следующей строчки – у нас это использование элемента 'infobox'. Второй способ приращения полосы загрузки – использование переменной окружения $COUNT, из которой dialog считывает текущее значение индикатора.

Остальные элементы dialog'а – календари, поля для ввода времени и тому подобное – просты, аналогичны в использовании и в особых комментариях не нуждаются.

В заключение напишем более полезный, чем предыдущие примеры, скрипт, добавляющий новые задания в очередь планировщика at. Наш скрипт будет предлагать на выбор два действия – выбрать исполняемый файл, который будет запущен через at, или ввести команду, которая также будет запущена в указанное время через at.

Для выбора исполняемого файла применяется диалоговое окно fselect. Оно имеет ряд особенностей – для перехода в нужную директорию необходимо ввести путь к ней в нижнее поле диалогового окна. Можно выбрать файл\каталог в панелях сверху и добавить его в поле снизу при помощи клавиши "Пробел".

Выбор времени и даты производится диалоговыми окнами timebox и calendar. Значения можно как вводить, так и выбирать, прокручивая их списки при помощи клавиш "Стрелка вверх" и "Стрелка вниз".

Скрипт состоит из трех основных функций – функции, производящей выбор файла, который надо запустить через at; функции, принимающей имя программы для исполнения; функции, которая узнает от пользователя время и дату и переводит их в формат, понятный утилите at.

Функция выбора файла производит проверку, является ли данный файл исполняемым. Если это не так, происходит повторный вывод на экран диалогового окна выбора файла до тех пор, пока не будет получен удовлетворительный результат – выбранный в очередной раз файл окажется исполняемым. Эта процедура производится следующим куском кода:

dialog --title 'add2at' --fselect "$HOME" 10 50 2>$TMPF
if [ "$?" -eq "1" ]; then
	nexit
fi
FILE2EXEC=$(cat $TMPF)
while [ ! -x "$FILE2EXEC" ]; do
	dialog --title 'add2at' --msgbox "$FILE2EXEC is not executable. Please choose \
	another one file" 40 50
	sleep 1
	dialog --title 'add2at' --fselect "$HOME" 10 50 2>$TMPF
	if [ "$?" -eq "1" ]; then
		nexit
	fi
	FILE2EXEC=$(cat $TMPF)
done


Возможно, подобная реализация и не оптимальна, зато проста и наглядна.


Проекты, где применяется dialog

Благодаря своей относительно простоте, dialog применяется во многих проектах, где используются shell-скрипты и важно успешное взаимодействие с пользователем. Самый большой (и главный) пример подобного проекта – установщик Slackware Linux, программа setup. Также можно привести в пример утилиту для работы с пакетами Slackware – pkgtool – она тоже написана с применением утилиты dialog (вообще, таковыми являются все скрипты из каталога /usr/lib/setup в Slackware).

Посмотреть на примеры использования dialog'а можно, скачав его исходные коды и заглянув в каталог examples. Там даны примеры использования практически для всех типов диалоговых окон.

Dialog является весьма неплохим выбором, если вы хотите сделать более простым использование вашего скрипта для неискушенных, в навыках использования командной оболочки, пользователей или же если вы хотите сделать некие действия более наглядными и удобными для однозначного восприятия различными людьми.



Загрузка

Имя Размер Метод загрузки
dialog.files.tar.gz 1,5KB HTTP

Источник ibm.com