В данной статье я хочу продемонстрировать как можно прикрутить простейший графический интерфейс к bash скрипту.
Предистория
Все хотя бы раз в жизни сталкивались с ксерокопированием документов. В продаже есть широкий выбор устройств копирования, начиная от устройств ксерокопирования и заканчивая МФУ, где в одном устройстве совмещены сканер, принтер и копир. При наличии сканера и принтера, можно использовать программу копирования. Данные программы идут в комплекте со многими моделями сканеров. Для дома я предпочел иметь последний вариант, т.к. устройство ксерокопирования копирует без полутонов, а МФУ, хоть и экономит место, при выходе из строя одного из компонентов (обычно принтер), придется выкидывать целиком, да и качество сканера у МФУ не очень.
Так же как и ко многим моделям сканеров, к моему сканеру Epson Perfection photo 2480 шла программа Epson copy utility, главным недостатком которой было наличие версии только под Windows. Поиск аналогичных программ под Linux ни к чему не привели.
На одном из форумов мне порекомендовали написать скрипт и даже помогли с написанием. Вот этот скрипт:
#! /bin/bash
SCANNER=`sane-find-scanner -q | sed -e 's/.*at /snapscan:/'` #Определяем активный первый попавшийся ЮСБ сканнер
TMPFILE="/tmp/scan.tiff" # временный файл куда сканируем
TMPFILE_PDF="/tmp/scan.pdf"
TMPFILE_PS="/tmp/scan.ps" # временный файл PostScript для печати
LOCKFILE="/tmp/copy.lock" #Файл блокировки
#Проверяем не запущена ли программа
#и создаем файл блокировки, чтобы случайно не запустить вторую копию
if ! lockfile-create --retry 2 -l $LOCKFILE; then
exit
fi
scanimage --device-name $SCANNER --format tiff --mode Gray -x 210 -y 297 --resolution 300 --brightness -3 -p > $TMPFILE
#Сканируем. Параметры сканирования смотрите в man scanimage
tiff2ps -z -w 8.27 -h 11.69 $TMPFILE | lp
lockfile-remove -l $LOCKFILE #удаляем файл блокировки
Прикручиваем интерфейс
У вышеуказанного скрипта был огромный недостаток — нельзя было указать количество копий. После небольшой переделки стало возможным указывать в командной строке количество копий, но это не устроило моих домочадцев, которые не желали лезть в консоль. Писать нативное приложение с интерфейсом я не хотел и не умел. Потом я узнал, что к bash скриптам можно прикрутить интерфейс через программы dialog, zenity, kdialog. Ну я попробовал переписать используя zenity + я добавил обработку различных ошибок. Оказалось добавление интерфейса не просто, а очень просто! Вот что из этого у меня вышло.
Сначала определяем переменные и блокируем.
SCANNER=`sane-find-scanner -q | sed -e 's/.*at /snapscan:/'` #Определяем активный первый попавшийся ЮСБ сканнер
DIALOG=zenity
TMPFILE="/tmp/scan.tiff" # временный файл куда сканируем
TMPFILE_PDF="/tmp/scan.pdf"
TMPFILE_PS="/tmp/scan.ps" # временный файл PostScript для печати
LOCKFILE="/tmp/copy.lock" #Файл блокировки
DLG_COUNT_TITLE="Количество копий"
DLG_COUNT_TEXT="Установите необходимое количество копий"
DLG_PROGRESS_TITLE="Процесс копирования"
DLG_PROGRESS_TEXT="Выполняю..."
MSG_START_PROCESS="Начинаю копирование со сканера $SCANNER"
MSG_SCAN="Сканирую"
MSG_PRINT="Отправка задания на печать"
MSG_COMPLETE="Задание отправлено на печать."
MSG_ERROR_LOCK="Ошибка: запущена другая копия программы, дождитесь пока программа закончит работу или закройте его."
MSG_ERROR_SCAN="Ошибка: не получилось сканировать, скорее всего сканер занят другим приложением или сканер не подключен."
MSG_ERROR_PRINT="Ошибка: не получилось распечатать."
После инициализации всех переменных скрипт спрашивает количество копий. Результат программа возвращает в консоль, но мы с помощью обратных одиночных кавычек (там где находиться русское «ё», но в английской раскладке) присваиваем результат переменной COPY_COUNT.
COPY_COUNT=`$DIALOG --scale
--title="$DLG_COUNT_TITLE"
--text="$DLG_COUNT_TEXT"
--min-value=1
--max-value=50
--value=1
--step=1`
Zenity возвратить код возврата, которая храниться в переменной $?.. Мы должны будем проверить его. Коды возврата: 0 — пользователь указал/ввел что то и нажал ОК; 1 — пользователь нажал «Отмена»; -1 — произошла ошибка. Целесообразно продолжать работу программы только при коде возврата 0, т.к. пользователь мог ошибочно запустить скрипт и у него должен быть выбор отмены.
if [[ "$?" == "0" ]]
then {
#полезный код
}
Так как процесс сканирования и печати достаточно «долгий» от нескольких секунд до нескольких минут, то надо как то показать на какой стадии идет процесс. При этом пользователь должен иметь возможность остановить процесс копирования на стадии сканирования. Для прогресс бара у zenity есть параметр --progress
. В результате предыдущий код приобретает вид:
if [[ "$?" == "0" ]]
then {
(
#полезный код
)| $DIALOG --progress
--title="$DLG_PROGRESS_TITLE"
--text="$DLG_PROGRESS_TEXT"
--percentage=0 --auto-close
}
чтобы прогрессбар двигался, нужно чтобы в блоке отмеченным комментарием «полезный код» выводились значения процента через echo, например echo 10
установит прогрессбар на 10%, echo 100
на 100%. Чтобы указать на какой стадии процесса мы находимся (сканирование, печать или завершение программы) в виде текста надо тоже использовать echo, но при этом мы должны добавить знак решетки в начале сообщения например echo "#Идет процесс сканирования" заставит вывести текст на прогресс баре.
И на последок уже добавляем команды сканирования и печати.
Заключение
В результате получилась программа которая имеет очень простой и понятный интерфейс и функционал не уступающей родной программе копирования от Epson.
#! /bin/bash
SCANNER=`sane-find-scanner -q | sed -e 's/.*at /snapscan:/'` #Определяем активный первый попавшийся ЮСБ сканнер
DIALOG=zenity
TMPFILE="/tmp/scan.tiff" # временный файл куда сканируем
TMPFILE_PDF="/tmp/scan.pdf"
TMPFILE_PS="/tmp/scan.ps" # временный файл PostScript для печати
LOCKFILE="/tmp/copy.lock" #Файл блокировки
DLG_COUNT_TITLE="Количество копий"
DLG_COUNT_TEXT="Установите необходимое количество копий"
DLG_PROGRESS_TITLE="Процесс копирования"
DLG_PROGRESS_TEXT="Выполняю..."
MSG_START_PROCESS="Начинаю копирование со сканера $SCANNER"
MSG_SCAN="Сканирую"
MSG_PRINT="Отправка задания на печать"
MSG_COMPLETE="Задание отправлено на печать."
MSG_ERROR_LOCK="Ошибка: запущена другая копия программы, дождитесь пока программа закончит работу или закройте его."
MSG_ERROR_SCAN="Ошибка: не получилось сканировать, скорее всего сканер занят другим приложением или сканер не подключен."
MSG_ERROR_PRINT="Ошибка: не получилось распечатать."
#Проверяем не запущена ли программа
if ! lockfile-create --retry 2 -l $LOCKFILE; then
$DIALOG --error --text "$MSG_ERROR_LOCK"
exit
fi
COPY_COUNT=`$DIALOG --scale
--title="$DLG_COUNT_TITLE"
--text="$DLG_COUNT_TEXT"
--min-value=1
--max-value=50
--value=1
--step=1`
if [[ "$?" == "0" ]]
then {
(
echo "# $MSG_START_PROCESS"
echo "10"
sleep 2
rm -f $TMPFILE
echo "# $MSG_SCAN"
echo "25"
scanimage --device-name $SCANNER --format tiff --mode Gray -x 210 -y 297 --resolution 300 --brightness -3 -p > $TMPFILE #Сканируем. Параметры сканирования смотрите в man scanimage
if [ $? != 0 ]; then
$DIALOG --error --text "$MSG_ERROR_SCAN"
exit
fi
echo "# $MSG_PRINT"
echo "75"
#Проверяем количество копий и печатаем
if [[ "$COPY_COUNT" == "1" ]]
then
tiff2ps -z -w 8.27 -h 11.69 $TMPFILE | lp
else
tiff2ps -z -w 8.27 -h 11.69 $TMPFILE | lp -n $COPY_COUNT
fi
if [ $? != 0 ]; then
$DIALOG --error --text "$MSG_ERROR_PRINT"
exit
fi
echo "# $MSG_COMPLETE"
echo "100"
sleep 2
) | $DIALOG --progress
--title="$DLG_PROGRESS_TITLE"
--text="$DLG_PROGRESS_TEXT"
--percentage=0 --auto-close || lockfile-remove -l $LOCKFILE
}
fi
lockfile-remove -l $LOCKFILE
Надеюсь мой скрипт окажется полезным для вас.
Автор: k1b0rg