Поиск по сайту:

Как добавить графический интерфейс в сценарии оболочки Linux


Вы можете использовать окна графического интерфейса, ползунки, переключатели, индикаторы выполнения и многое другое в своих сценариях Bash. Узнайте, как использовать набор инструментов zenity и обновить свои сценарии Bash. Мы покажем вам, как это сделать.

Сценарии Bash — это мощный язык программирования, и, поскольку он встроен в оболочку Bash, он легко доступен для всех. На этом языке легко начать программировать. Поскольку он интерпретируемый, вам не нужно компилировать сценарии. Как только вы отредактировали файл сценария и сделали его исполняемым, вы можете запустить его. Это делает цикл кодирования, запуска и отладки достаточно эффективным.

У людей есть две основные жалобы на сценарии Bash, и первая — это скорость. Поскольку оболочка Bash интерпретирует команды сценария, они выполняются не так быстро, как скомпилированный код. Однако это все равно, что жаловаться на то, что трактор не так быстр, как автомобиль; они предназначены для разных вещей.

Однако есть два вида скорости. Часто вы можете составить быстрый сценарий и использовать его для выполнения задачи гораздо быстрее, чем разрабатывать решение на скомпилированном языке, таком как C.

Вторая претензия, которую люди предъявляют к сценариям Bash, связана с пользовательским интерфейсом — это окно терминала. Конечно, иногда интерфейс не имеет значения. Если единственным человеком, который когда-либо будет использовать сценарий, является его автор, интерфейс, вероятно, не так важен. Это также не имеет значения для сценариев, выполняющих фоновую и пакетную обработку. Как правило, такие скрипты не требуют особого взаимодействия с пользователем (если оно вообще требуется).

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

Приложение Zenity

zenity позволяет включать в сценарии Bash широкий спектр элементов графического интерфейса. Это мощный набор инструментов, который придает вашим сценариям современный вид и современный знакомый внешний вид.

zenity предустановлен в дистрибутивах Ubuntu, Fedora и Manjaro. Это часть GNOME. Если вы используете KDE, вы можете вместо этого проверить  kdialog  , хотя zenity работает в любой среде рабочего стола.

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

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

Диалоговое окно календаря

Диалоговое окно календаря позволяет кому-то выбрать дату. Чтобы создать его с помощью zenity, требуется одна команда из двух слов:

zenity --calendar

Появится диалоговое окно календаря. У него есть все функции, которые вы ожидаете от стандартного средства выбора даты. Вы можете изменить месяц и год и щелкнуть день, чтобы выбрать эту дату. По умолчанию сегодняшняя дата выделяется при появлении окна.

Нажмите «ОК», чтобы закрыть диалоговое окно, и выберите выделенную дату. Двойной щелчок по дате делает то же самое.

Если вы не хотите делать выбор даты, нажмите «Отмена», нажмите клавишу «Esc» на клавиатуре или закройте диалоговое окно.

В приведенном выше примере выбрано 19 августа 2019 года. Если пользователь нажимает «ОК», календарь закрывается, а выбранная дата печатается в окне терминала.

Вы можете игнорировать строку «GTKDialog отображается без временного родителя. Это обескураживает».

GTK означает GIMP Tool Kit, набор инструментов, используемый для разработки интерфейса GNOME. Первоначально он был разработан авторами программы обработки изображений GNU (GIMP). GNU расшифровывается как GNU Not Unix.

Движок GTK предупреждает авторов zenity о том, что они использовали компонент GTK нестандартным способом.

Захват значения даты

Печать даты на терминале мало что для нас делает. Если мы собираемся вызывать этот календарь из одного из наших скриптов, нам нужно зафиксировать выбранное значение даты, чтобы мы могли сделать с ним что-то полезное в нашем скрипте. Мы также немного настроим календарь.

Мы будем использовать следующие параметры с календарем. Все они должны использоваться с двойным дефисом «–»:

  • –текст: задает строку текста для отображения в календаре. Он заменяет вариант по умолчанию Выберите дату из списка ниже.
  • –title: устанавливает заголовок диалогового окна календаря.
  • –день: устанавливает день, который выбирается при открытии календаря.
  • –месяц: устанавливает месяц, который выбирается при открытии календаря.
  • -year: устанавливает год, который выбирается при открытии календаря.

Мы используем переменную с именем ChosenDate, чтобы зафиксировать дату, возвращенную из календаря. И мы используем echo $ChosenDate, чтобы вывести эту дату в окно терминала.

Да, мы достигли того же результата в предыдущем примере, но здесь у нас есть выбранная дата, сохраненная в переменной. В предыдущем примере он был напечатан и забыт.

ChosenDate=$(zenity -- calendar --text "Choose a date" --title "How-To Geek Rota" --day 1 -- month 9 --year 2019); echo $ChosenDate

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

Мы также можем настроить формат строки даты, возвращаемой при выборе. За параметром --date-format должен следовать спецификатор формата. Это строка токенов, определяющих данные и форматы, которые должны быть включены в вывод. Токены такие же, как те, которые используются с функцией языка C strftime(), и их существует огромный выбор.

Токены, которые мы используем:

  • %A: полное название дня недели.
  • %d: день месяца в виде цифры.
  • %m: месяц в виде цифры.
  • %y: год в виде двух цифр (без века).

ChosenDate=$(zenity -- calendar --text "Choose a date" --title "How-To Geek Rota" --date-format="%A %d/%m/%y" --day 1 -- month 9 --year 2019); echo $ChosenDate

Кто-то выбирает дату:

И дата возвращается в нашем формате. Он показывает название дня недели, за которым следует дата в европейском порядке: день, месяц, год.

Диалоговое окно выбора файла: выбор файла

Диалоговые окна выбора файла довольно сложны. Люди могут просмотреть файловую систему, выделить файл или файлы, а затем нажать «ОК», чтобы выбрать эти файлы или полностью отменить выбор.

zenity предоставляет все эти функции и многое другое. И им так же легко пользоваться, как и диалоговым окном календаря.

Новые параметры, которые мы собираемся использовать:

  • –file-selection: сообщает zenity, что мы хотим использовать диалоговое окно выбора файла.
  • –несколько: позволяет выбрать несколько файлов.
  • –file-filter: сообщает диалоговому окну файла, какие типы файлов отображать.

zenity --file-selection --tile "How-To Geek" --multiple --file-filter='*.mm *.png *.page *.sh *.txt'

Диалоговое окно выбора файла так же функционально, как и любое другое окно выбора файла.

Пользователь может просмотреть файловую систему и выбрать файл по своему выбору.

Мы перешли в новый каталог и выбрали файл с именем «button_hybrid.png».

Когда вы нажимаете «ОК», диалоговое окно выбора файла закрывается, а имя файла и путь печатаются в окне терминала.

Если вам нужно использовать имя файла в какой-либо дальнейшей обработке, вы можете зафиксировать его в переменной, как вы сделали это для даты из календаря.

Диалоговое окно выбора файла: сохранение файла

Если мы добавим одну опцию, мы можем превратить диалоговое окно выбора файла в диалоговое окно сохранения файла. Опция --save. Мы также собираемся использовать параметр --confirm-overwrite . Это побуждает человека подтвердить, что он хочет перезаписать существующий файл.

Response=$(zenity --file-selection --save --confirm-overwrite); echo $Response

Появится диалоговое окно сохранения файла. Обратите внимание, что есть текстовое поле, где кто-то может ввести имя файла.

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

В приведенном выше примере пользователь выделил существующий файл.

Когда он нажимает «ОК», появляется диалоговое окно подтверждения с просьбой подтвердить, что он хочет заменить существующий файл. Обратите внимание, что имя файла отображается в диалоговом окне предупреждения. Именно такое внимание к деталям придает zenity профессиональный вид.

Если бы мы не использовали параметр --confirm-overwrite, файл был бы автоматически перезаписан.

Имя файла хранится в переменной Response, которая выводится в окно терминала.

Диалоговые окна уведомлений

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

Чтобы создать диалоговое окно с сообщением об ошибке, используйте следующую команду:

zenity --error --width 300 --text "Permission denied. Cannot write to the file."

Новые параметры, которые мы используем:

  • –error: сообщает zenity, что мы хотим использовать диалоговое окно с ошибкой.
  • –width: устанавливает начальную ширину окна.

Диалоговое окно ошибки отображается с указанной шириной. Он использует стандартный значок ошибки GTK.

Чтобы создать информационное диалоговое окно, используйте следующую команду:

zenity --info --width 300 --text "Update complete. Click OK to continue."

Мы используем новый параметр --info, который указывает zenity создать информационное диалоговое окно.

Чтобы создать диалоговое окно вопроса, используйте следующую команду:

zenity --question --width 300 --text "Are you happy to proceed?"; echo $?

Мы используем новый параметр --question, который указывает zenity создать диалоговое окно с вопросом.

$? — это специальный параметр. Он содержит возвращаемое значение из последнего запущенного конвейера переднего плана. В общих чертах это значение последнего закрытого процесса. Нулевое значение означает «ОК», а значение, равное единице или более, означает «Отмена».

Это общая техника, которую вы можете применить к любому диалоговому окну zenity. Проверяя это значение в своем скрипте, вы можете определить, должны ли данные, возвращаемые из диалогового окна, обрабатываться или игнорироваться.

Мы нажали «Да», поэтому код возврата — ноль, указывающий «ОК».

Чтобы создать диалоговое окно с предупреждением, используйте следующую команду:

zenity --warning --title "Low Hard Drive Space" --width 300 --text "There may not be enough hard drive space to save the backup."

Мы используем новую опцию --warning, которая указывает zenity создать диалоговое окно с предупреждением.

Появится диалоговое окно с предупреждением. Это не вопрос, так что у него только одна кнопка.

Диалоговое окно прогресса

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

Индикатор выполнения продвигается в соответствии со значениями, переданными в него из вашего скрипта. Чтобы продемонстрировать принцип, используйте следующую команду:

(for i in $(seq 0 10 100); do echo $i; sleep 1; done)

Команда разбивается следующим образом:

  • Команда seq выполняет последовательность от 0 до 100 с шагом 10.
  • На каждом этапе значение сохраняется в переменной i. Это печатает в окно терминала.
  • Команда приостанавливается на одну секунду из-за команды sleep 1.

Мы можем использовать это с диалоговым окном прогресса zenity, чтобы продемонстрировать индикатор выполнения. Обратите внимание, что мы передаем вывод предыдущей команды в zenity:

(for i in $(seq 0 10 100); do echo $i; sleep 1; done) | zenity --progress --title "How-To Geek" -- auto-close

Новые параметры, которые мы используем:

  • –progress: сообщает zenity, что мы хотим использовать диалоговое окно прогресса.
  • –auto-close: закрывает диалоговое окно, когда индикатор выполнения достигает 100 процентов.

Появляется диалоговое окно прогресса, и полоса приближается к 100 процентам с паузой в одну секунду между каждым шагом.

Мы можем использовать эту концепцию передачи значений в zenity, чтобы включить диалоговое окно прогресса в скрипт.

Введите этот текст в редакторе и сохраните его как «progress.sh».

!/bin/bash

function work-list () {

echo "# First work item" 
echo "25"
sleep 1

echo "# Second work item" 
echo "50"
sleep 1

echo "# Third work item" 
echo "75"
sleep 1

echo "# Last work item" 
echo "100"
sleep 1

}

work-list | zenity --progress --title "How-To Geek" --auto-close

exit 0

Вот разбивка сценария:

  • Сценарий определяет функцию с именем work-list. Здесь вы размещаете свои команды и инструкции для выполнения реальной работы. Замените все команды sleep 1 своими реальными.
  • zenity принимает строки echo \# ...\ и отображает их в диалоговом окне хода выполнения. Измените текст этих строк, чтобы они передавали информативные сообщения пользователю.
  • Строки echo, содержащие числа, такие как echo \25\ , также принимаются zenity и устанавливают значение индикатор выполнения.
  • Функция рабочего списка вызывается и передается в zenity.

Используйте эту команду, чтобы сделать скрипт исполняемым:

chmod +x progress.sh

Используйте эту команду для запуска скрипта:

./progress.sh

Сценарий запускается, и текстовое сообщение изменяется по мере выполнения каждой фазы сценария. Индикатор выполнения постепенно приближается к 100 процентам.

Диалоговое окно «Масштаб»

Диалоговое окно масштаба позволяет кому-то перемещать ползунок, чтобы выбрать числовое значение. Это означает, что она не может ввести слишком высокое или слишком низкое значение.

Мы используем следующие новые параметры:

  • –scale: сообщает zenity, что мы хотим использовать диалоговое окно масштаба.
  • –min-value: устанавливает минимальное значение шкалы.
  • –max-value: устанавливает максимальное значение шкалы.
  • –step: задает величину перемещения ползунка при использовании клавиш со стрелками. Это не влияет на перемещение ползунка, если кто-то использует мышь.
  • –value: устанавливает начальное значение и положение ползунка.

Это команда, которую мы используем:

Response=$(zenity --scale --title "How-To Geek" --text "Select magnification." --min-value=0 --max-value=30 --step=3 --value15); echo $Response

Появится диалоговое окно ползунка с ползунком, установленным на 15.

Пользователь может перемещать ползунок, чтобы выбрать новое значение.

Когда она нажимает «ОК», значение передается в переменную Response и печатается в окне терминала.

Диалоговое окно ввода

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

Мы используем следующие новые параметры:

  • –entry: сообщает zenity, что мы хотим использовать диалоговое окно ввода.
  • –entry-text: вы можете использовать это, если хотите ввести предлагаемое значение в поле ввода текста. Мы используем «», чтобы заполнить пустое поле. Это не обязательно, но мы хотели задокументировать этот параметр.

Полная команда выглядит так:

Response=$(zenity --entry --text "Enter your search term" --title "Howe-To Geek" --entry-text=""); echo $Response

Появится простое диалоговое окно, содержащее поле ввода текста.

Кто-то может набирать и редактировать текст.

Когда он нажимает «ОК», введенное им значение присваивается переменной Response. Мы используем эхо для вывода значения переменной в окно терминала.

Собираем все вместе

Давайте объединим эти методы и создадим функциональный скрипт. Сценарий выполнит сканирование информации об оборудовании и представит результаты пользователю в прокручиваемом текстовом окне. Она может выбрать длинный или короткий тип сканирования.

Для этого скрипта мы будем использовать три типа диалоговых окон, два из которых для нас новые:

  • Первое — это диалоговое окно со списком. Это позволяет кому-то сделать выбор.
  • Второе – это диалоговое окно с информацией о ходе выполнения, которое сообщает пользователю, что что-то происходит, и ему следует подождать.
  • Третье окно представляет собой текстовое информационное окно, в котором отображаются результаты для пользователя.

Введите этот текст в редакторе и сохраните его как «hardware-info.sh».

#!/bin/bash

# Display hardware listing for this computer

TempFile=$(mktemp)

ListType=`zenity --width=400 --height=275 --list --radiolist \
     --title 'Hardware Scan' \
     --text 'Select the scan type:' \
     --column 'Select' \
     --column 'Scan Type' TRUE "Short" FALSE "Long"`

if [[ $? -eq 1 ]]; then

  # they pressed Cancel or closed the dialog window 
  zenity --error --title="Scan Declined" --width=200 \
       --text="Hardware scan skipped"
  exit 1
 
elif [ $ListType == "Short" ]; then

  # they selected the short radio button 
  Flag="--short"
 
else

  # they selected the long radio button 
  Flag="" 
fi

# search for hardware info with the appropriate value in $Flag
hwinfo $Flag | tee >(zenity --width=200 --height=100 \
     --title="Collating Information" --progress \
     --pulsate --text="Checking hardware..." \
     --auto-kill --auto-close) >${TempFile}
 
# Display the hardware info in a scrolling window
zenity --width=800 --height=600 \
     --title "Hardware Details" \
     --text-info --filename="${TempFile}"
 
exit 0

Используйте эту команду, чтобы сделать его исполняемым:

chmod +x hardware-info.sh

Этот скрипт создает временный файл, и имя файла хранится в переменной TempFile:

TempFile=$(mktemp)

Сценарий использует параметр --list для создания диалогового окна zenity, называемого диалоговым окном списка. Символы «\» в конце строк указывают сценарию обрабатывать их как одну длинную строку, обернутую вокруг. Вот процесс:

  • Мы указываем ширину и высоту окна.
  • Диалоговое окно списка поддерживает столбцы. Опция --radiolist делает первый столбец столбцом переключателей.
  • Мы устанавливаем заголовок и текстовую подсказку для окна.
  • Мы установили заголовок первого столбца Выбрать. Содержимое этого столбца будет переключателями.
  • Мы установили заголовок второго столбца как Выбрать и предоставили содержимое второго столбца. Этот столбец содержит две текстовые метки: «Короткая» и «Длинная». Индикаторы TRUE и FALSE означают, что при появлении диалогового окна по умолчанию выбран вариант «Короткий».
  • Мы сохраняем результат этого диалогового окна в переменной с именем ListType.

ListType=`zenity --width=400 --height=275 --list --radiolist \ 
     --title 'Hardware Scan' \ 
     --text 'Select the scan type:' \ 
     --column 'Select' \ 
     --column 'Scan Type' TRUE "Short" FALSE "Long"`

Если пользователь нажимает «Отмена», нам не нужно проверять значение в ListType, мы можем просто выйти. Если он нажимает «ОК», нам нужно выяснить, выбрал ли он переключатель «Короткий» или «Длинный»:

  • Специальный параметр $? равен нулю, если пользователь нажал ОК. Он равен единице, если он нажал «Отмена» или закрыл окно.
  • Если оно равно единице, сценарий отображает диалоговое окно с информацией об ошибке и завершает работу. Если он нажмет ОК, мы перейдем к проверке значения в переменной ListType.
  • Если переменная ListType содержит значение «Short», сценарий устанавливает для переменной Flag значение «–short».
  • Если переменная ListType не содержит значение «Короткий», она должна содержать значение «Длинный». Сценарий устанавливает переменную с именем Flag равной «», что является пустой строкой.
  • Сценарий использует переменную Flag в следующем разделе.

if [[ $? -eq 1 ]]; then 

  # they pressed Cancel or closed the dialog window 
  zenity --error --title="Scan Declined" --width=200 \ --text="Hardware scan skipped" 
  exit 1 

elif [ $ListType == "Short" ]; then 

 # they selected the short radio button 
 Flag="--short" 

else 

 # they selected the long radio button 
 Flag="" 
fi

Теперь, когда скрипт знает, какой тип сканирования хочет пользователь, мы можем выполнить сканирование информации об оборудовании:

  • Сценарий вызывает команду hwinfo и передает ей значение в переменной Flag.
  • Если Flag содержит «–short», команда hwinfo выполняет короткое сканирование. Если значение Flag равно «», ничего не передается в hwinfo и по умолчанию выполняется длительное сканирование.
  • Сценарий направляет вывод из hwinfo в tee. tee отправляет выходные данные в zenity и в TempFile.
  • Сценарий создает диалоговое окно индикатора выполнения. Он устанавливает ширину и высоту диалогового окна, а также заголовок и текст подсказки.
  • Сценарий не может знать заранее, какой объем информации выдаст команда hwinfo, поэтому он не может правильно настроить индикатор выполнения на 100 процентов. Параметр --pulsate приводит к тому, что в диалоговом окне прогресса отображается движущийся индикатор. Это информирует пользователя о том, что что-то происходит, и ему следует подождать.
  • Параметр --auto-kill завершает выполнение скрипта, если кто-то нажимает кнопку Отмена.
  • Параметр --auto-close приводит к автоматическому закрытию диалогового окна хода выполнения по завершении отслеживаемого процесса.

# search for hardware info with the appropriate value in $Flag
hwinfo $Flag | tee >(zenity --width=200 --height=100 \
     --title="Collating Information" --progress \
     --pulsate --text="Checking hardware..." \
     --auto-kill --auto-close) >${TempFile}

Когда сканирование hwinfo завершается, скрипт вызывает zenity для создания диалогового окна с текстовой информацией с опцией --text-info . В диалоговом окне текстовой информации отображается содержимое файла TempFile:

  • Сценарий задает ширину и высоту диалогового окна и текста заголовка.
  • Опция --flename используется для чтения содержимого файла, содержащегося в переменной TempFIle.

# Display the hardware info in a scrolling window 
zenity --width=800 --height=600 \ 
     --title "Hardware Details" \ 
     --text-info --filename="${TempFile}"

Когда пользователь закрывает диалоговое окно с текстовой информацией, скрипт завершает работу.

exit 0

Давайте зажжем его и посмотрим.

./hardware-info.sh

Появится окно со списком. По умолчанию выбран вариант «Короткий».

Давайте выберем «Длинный», а затем нажмите «ОК».

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

Когда сканирование оборудования будет завершено, появится диалоговое окно с текстовой информацией и сведениями о сканировании.

Нажмите «ОК».

Даже несгибаемый жокей командной строки должен признать, что пара диалоговых окон с графическим интерфейсом могут придать скромному сценарию Bash профессиональный вид.